IngenierĂa del software
IngenierĂa del software Benet Campderrich Falgueras
Primera edición: abril 2003 © Fundació per a la Universitat Oberta de Catalunya © Benet Campderrich Falgueres, del texto © Editorial UOC, de esta edición Aragón, 182, 08011 Barcelona Material realizado por Eureca Media, SL Impresión: Diseño: Manel Andreu ISBN: 84-8429-793-4, del producto ISBN: 84-8318-997-6, del libro Depósito legal:
Ninguna parte de esta publicación, incluido el diseño general y la cubierta, puede ser copiada, reproducida, almacenada o transmitida de ninguna forma, ni por ningún medio,sea éste eléctrico, químico, mecánico, óptico, grabación, fotocopia, o cualquier otro, sin la previa autorización escrita de los titulares del copyright.
Autor Benet Campderrich Falgueras Doctor en IngenierĂa Industrial. Especializado en ingenierĂa del software y bases de datos. Profesor titular de la Universidad Rovira i Virgili.
© Editorial UOC
7
Índice
Índice
Presentación ................................................................................................... 13
Capítulo I. Introducción a la ingeniería del software OO ................ 15 1. Qué 1.1. 1.2. 1.3. 2.
3.
4. 5.
es la ingeniería del software ............................................................. El software como producto industrial.................................................. La ingeniería del software .................................................................... Los grandes problemas de la ingeniería del software: la calidad y la productividad ............................................................... El ciclo de vida del software ..................................................................... 2.1. El ciclo de vida clásico......................................................................... 2.2. Los ciclos de vida iterativos e incrementales ...................................... Desarrollo estructurado y desarrollo orientado a objetos ..................... 3.1. Los métodos estructurados .................................................................. 3.2. Los métodos orientados a objetos ....................................................... 3.3. Los métodos formales.......................................................................... Las herramientas CASE ............................................................................. El OMG y el UML ....................................................................................... 5.1. El Object Management Group (OMG) .................................................... 5.2. Unified Modeling Language (UML) ........................................................
15 16 17 17 19 20 23 28 28 28 30 30 32 32 32
Conclusiones ................................................................................................... 35
Capítulo II. UML (I): el modelo estático ................................................ 37 1. 2. 3. 4.
Concepto de modelo estático y diagrama de clases ............................... Clasificadores ............................................................................................. Paquetes...................................................................................................... Clase y conceptos afines ........................................................................... 4.1. Representación ampliada de las clases ................................................
37 39 40 43 43
© Editorial UOC
8
Ingeniería del software
4.2. La herencia en el análisis y el diseño .................................................. 4.3. Variantes en el concepto de clase ....................................................... 4.4. Interfaces ............................................................................................. 5. Representación de los objetos .................................................................. 6. Relaciones entre clases .............................................................................. 6.1. Asociaciones ........................................................................................ 6.2. Agregaciones y composiciones ............................................................ 6.3. Relaciones de dependencia ................................................................. 7. Comentarios y restricciones ..................................................................... 7.1. Comentarios ........................................................................................ 7.2. Restricciones ........................................................................................
48 51 54 56 57 57 63 66 67 67 67
Conclusiones ................................................................................................... 69
Capítulo III. UML(II): el modelo dinámico y de implementación ............................................................................. 71 1. El diagrama de estados.............................................................................. 71 1.1. Conceptos básicos ............................................................................... 72 1.2. Notaciones básicas............................................................................... 74 1.3. Transiciones complejas ....................................................................... 78 1.4. Estados compuestos............................................................................. 79 1.5. Notación ampliada del estado............................................................. 82 2. El diagrama de casos de uso ..................................................................... 83 2.1. Actores ................................................................................................. 83 2.2. Concepto de caso de uso ..................................................................... 85 2.3. Relaciones entre casos de uso.............................................................. 86 2.4. Notación .............................................................................................. 87 3. Los diagramas de interacción................................................................... 88 3.1. Interacciones y colaboraciones ........................................................... 88 3.2. El diagrama de colaboración ............................................................... 93 3.3. El diagrama de secuencias ................................................................... 95 4. El diagrama de actividades....................................................................... 99 4.1. Elementos específicos .......................................................................... 99 5. Los diagramas de implementación ........................................................ 102 5.1. El diagrama de componentes ............................................................ 102 5.2. El diagrama de despliegue ................................................................. 105 Conclusiones ................................................................................................. 107
© Editorial UOC
9
Índice
Capítulo IV. Recogida y documentación de requisitos ................... 109 1. Los requisitos ........................................................................................... 1.1. Clases de requisitos ........................................................................... 2. Fuentes de información .......................................................................... 3. Pasos de la recogida y documentación de requisitos ........................... 3.1. El contexto del software ..................................................................... 3.2. Los guiones ........................................................................................ 3.3. Identificación de los actores.............................................................. 3.4. Identificación de los casos de uso ..................................................... 3.5. Identificación de las relaciones entre casos de uso ........................... 3.6. Identificación de las relaciones de especialización entre actores ..... 3.7. La documentación de los casos de uso ............................................. 4. La recogida y documentación de requisitos de la interfaz de usuario ... 4.1. Concepto de interfaz de usuario ....................................................... 4.2. Identificación de las restricciones técnicas ....................................... 4.3. Elaboración de los perfiles de usuario............................................... 4.4. Documentación de las tareas actuales y futuras ............................... 4.5. Comparación entre tareas y casos de uso ......................................... 4.6. Especificaciones de usabilidad .......................................................... 5. Ejemplo..................................................................................................... 5.1. Información inicial ........................................................................... 5.2. Modelo del dominio.......................................................................... 5.3. Modelo del negocio ........................................................................... 5.4. El glosario del modelo del negocio ................................................... 5.5. Los guiones ........................................................................................ 5.6. Casos de uso ...................................................................................... 5.7. Requisitos de la interfaz de usuario...................................................
110 110 111 112 112 114 114 115 116 118 118 120 120 121 121 122 123 124 124 125 125 126 128 129 130 135
Conclusiones ................................................................................................. 139
Capítulo V. Análisis orientado a objetos ............................................. 141 1. El papel del análisis................................................................................. 1.1. La relación entre la recogida de requisitos y el análisis .................... 1.2. La relación entre el análisis y el diseño............................................. 1.3. La utilidad del análisis....................................................................... 2. Paquetes de análisis y paquetes de servicios ......................................... 2.1. Los paquetes de análisis ....................................................................
142 142 142 143 144 145
© Editorial UOC
10
Ingeniería del software
2.2. Los paquetes de servicios................................................................... 3. Revisión de los casos de uso ................................................................... 4. Especificación de las clases de análisis .................................................. 4.1. Identificación de las clases de entidades........................................... 4.2. Especificación de los atributos de las clases de entidades................. 4.3. Identificación de las relaciones entre clases...................................... 4.4. Identificación de las clases de frontera, las clases de control y de las operaciones. Diagrama estático de análisis .......................... 5. Especificación formal de los casos de uso ............................................. 6. Análisis de la interfaz de usuario ........................................................... 7. Ejemplo..................................................................................................... 7.1. Revisión de los casos de uso .............................................................. 7.2. Paquetes de análisis y de servicios .................................................... 7.3. Identificación de las clases de entidades........................................... 7.4. Especificación de los atributos de las clases de entidades................. 7.5. Relaciones .......................................................................................... 7.6. Identificación de las clases de frontera, las clases de control y de las operaciones........................................................................... 7.7. Especificación formal de los casos de uso ......................................... 7.8. Análisis de la interfaz de usuario.......................................................
145 146 147 148 150 151 158 158 159 160 160 160 161 162 163 166 169 171
Conclusiones ................................................................................................. 175
Capítulo VI. Diseño orientado a objetos.............................................. 177 1. El papel del diseño .................................................................................. 1.1. La relación entre el diseño y la realización ....................................... 1.2. La utilidad del diseño ........................................................................ 2. La reutilización ........................................................................................ 2.1. La reutilización de clases ................................................................... 2.2. La reutilización de componentes ...................................................... 2.3. Los patrones ...................................................................................... 2.4. Marcos de aplicaciones...................................................................... 3. El diseño arquitectónico ......................................................................... 3.1. Establecimiento de la configuración de la red .................................. 3.2. Establecimiento de los subsistemas................................................... 4. El diseño de los casos de uso ..................................................................
178 178 179 179 179 180 180 192 193 194 194 195
© Editorial UOC
11
5. Revisión del diagrama estático de diseño ............................................. 5.1. Normalización de los nombres ......................................................... 5.2. Reutilización de clases ....................................................................... 5.3. Adaptación de la herencia en el nivel soportado por el lenguaje de programación ............................................................................... 5.4. Sustitución de las interfaces .............................................................. 5.5. Cambios para la mejora del rendimiento ......................................... 5.6. Especificación de las operaciones implícitas..................................... 5.7. Referencias a las clases de frontera.................................................... 5.8. La clase inicial ................................................................................... 5.9. Cohesión y acoplamiento ................................................................. 6. Diseño de la persistencia ........................................................................ 6.1. Persistencia con bases de datos orientadas a objetos ........................ 6.2. El modelo para bases de datos relacionales y ficheros clásicos: alternativas ........................................................................................ 6.3. Persistencia con bases de datos object-relational ................................ 7. Diseño de la interfaz gráfica de usuario ................................................ 7.1. Elementos y funcionamiento de la interfaz gráfica de usuario ........ 7.2. El diseño de las interfaces gráficas .................................................... 8. Diseño de los subsistemas ....................................................................... 9. Ejemplo..................................................................................................... 9.1. El diseño arquitectónico ................................................................... 9.2. El diseño de los casos de uso ............................................................. 9.3. El diagrama estático de diseño .......................................................... 9.4. El diseño de la persistencia ............................................................... 9.5. El diseño de la interfaz de usuario .................................................... 9.6. El diseño de los subsistemas..............................................................
Índice
196 197 198 198 201 201 202 202 203 203 205 206 206 215 216 217 236 243 244 244 244 249 251 254 258
Conclusiones ................................................................................................. 260
Capítulo VII. Introducción al software distribuido ........................ 261 1. Entornos distribuidos y entornos abiertos ............................................ 1.1. Objetivos de los entornos distribuidos ............................................. 1.2. Importancia de las normas en los entornos distribuidos ................. 1.3. Concepto de sistema abierto ............................................................. 2. Entornos cliente/servidores clásicos...................................................... 2.1. Ventajas e inconvenientes de la arquitectura cliente/servidor ......... 2.2. Arquitecturas cliente/servidor de dos capas...................................... 2.3. Arquitecturas de más de dos capas....................................................
261 262 263 263 264 265 266 267
© Editorial UOC
12
Ingeniería del software
3. Entornos con middleware: CORBA ........................................................ 3.1. Concepto de middleware.................................................................... 3.2. CORBA ............................................................................................... 4. RMI............................................................................................................ 4.1. Mecanismos de una invocación remota ........................................... 5. Documentos compuestos distribuidos: DCOM..................................... 5.1. Concepto de documento compuesto ................................................ 5.2. Aspectos de la gestión de los documentos compuestos.................... 5.3. OLE, COM y DCOM .......................................................................... 6. Desarrollo del software distribuido........................................................ 6.1. El análisis de requisitos en el caso de software distribuido ............... 6.2. La distribución de los objetos ...........................................................
268 268 269 298 298 299 299 300 301 308 308 308
Bibliografía.................................................................................................... 312 Glosario ......................................................................................................... 314
© Editorial UOC
13
Presentación
Presentación
La ingeniería del software comprende los métodos y las técnicas que se utilizan en el desarrollo profesional del software. Se trata de un campo muy amplio, del cual esta materia sólo trata una parte. La ingeniería del software consta principalmente de dos familias de técnicas: • Las estructuradas, cronológicamente las más antiguas. • Las orientadas a objetos (OO), que constituyen la parte principal de esta obra, con las exclusiones mencionadas. El resto de la obra es una introducción a la ingeniería del software. La tecnología de elaboración de software orientado a objetos ha tenido la mayor parte de su desarrollo desde 1985 hasta la actualidad. Como suele pasar con toda nueva tecnología, al principio aparecen muchas técnicas alternativas y el paso del tiempo comporta que muchas se abandonen y sólo quede una o algunas que llegan a ser un estándar, oficial o de hecho. Parece que la tecnología orientada a objetos ha alcanzado hace unos pocos años esta situación, al menos en lo que respecta al modelo básico, del cual existe el estándar denominado UML, ya ampliamente aceptado y utilizado. Éste es el modelo que utilizamos. Además del modelo utilizado, otro aspecto fundamental del desarrollo de software es el método, ya que, si utilizamos el mismo modelo, podemos imaginar muchos métodos diferentes que utilizan las notaciones del modelo en otro orden o para otros propósitos distintos. A diferencia del caso del modelo básico, es poco probable que se imponga un método como estándar; como mucho se puede establecer como estándar legal la presentación de una determinada documentación elaborada según un modelo fijado, pero la manera como se trabaje para elaborarla siempre tendrá un margen de libertad amplio.
© Editorial UOC
14
Ingeniería del software
En esta obra se ha optado por seguir un método inspirado en el denominado Rational Unified Process, porque éste es bastante elaborado y coherente y, además, ha sido desarrollado esencialmente por el mismo equipo que desarrolló el UML, lo cual ofrece una cierta garantía de coherencia entre el método y el modelo. Se puede considerar que esta obra tiene una parte básica, un núcleo y una conclusión: • La parte básica comprende unos conocimientos fundamentales, que son el capítulo “Introducción a la ingeniería del software OO”, dedicado a los conceptos generales de la ingeniería del software; el capítulo “UML (I): el modelo estático” y el capítulo “UML (II): el modelo dinámico y de implementación”. • El núcleo de la obra está constituido por los capítulos “Recogida y documentación de requisitos”, “Análisis orientado a objetos” y “Diseño orientado a objetos”. • La conclusión es el capítulo “Introducción al software distribuido”, que ofrece una visión general de la tecnología del software distribuido orientado a objetos. Este tema conduce a introducir no solamente la problemática y las técnicas directamente relacionadas con la distribución del software, sino también conceptos que tienen un campo de aplicación más amplio.
© Editorial UOC
15
Capítulo I. Introducción a la...
Capítulo I
Introducción a la ingeniería del software OO
En este capítulo se empieza a introducir el concepto de ingeniería de software y a presentar su problemática. Se describe con detalle el ciclo de vida clásico o en cascada, y se presentan los modelos de ciclo de vida alternativos, en especial los conocidos como modelos iterativos e incrementales, entre los cuales se describe el ciclo de vida del Rational Unified Process. Se definen también las dos grandes líneas tecnológicas actuales en el desarrollo de software: el desarrollo estructurado y el desarrollo orientado a objetos, y se introduce el concepto de herramienta CASE. El capítulo termina con la presentación del origen y estatus del modelo estándar UML, el modelo orientado a objetos que se utiliza en esta obra, y del OMG, la organización responsable del mismo.
1. Qué es la ingeniería del software
Un sistema de software, denominado también aplicación o simplemente software, es un conjunto integrado de programas que en su forma definitiva se pueden ejecutar, pero comprende también las definiciones de estructuras de datos (por ejemplo, definiciones de bases de datos) que utilizan estos programas y también la documentación referente a todo ello (tanto la documentación de ayuda en el uso del software para sus usuarios como la documentación generada durante su construcción, parte de la cual también servirá para su mantenimiento posterior).
© Editorial UOC
16
Ingeniería del software
1.1. El software como producto industrial
Un software no es una obra de arte, sino un producto de consumo utilitario y masivo; para una empresa o trabajador autónomo, el software es un medio auxiliar que interviene de manera más o menos indirecta, pero a menudo imprescindible, en su gestión y cada vez más en su proceso productivo; también existe, como todos sabemos, un consumo privado de software. Por tanto, se puede considerar plenamente como un producto industrial. Por ejemplo... … los bancos, las industrias de fabricación en serie, las empresas de comercio electrónico, etc. actualmente no podrían funcionar sin software.
Sin embargo, es un producto industrial con algunas características especiales. En primer lugar, es mucho más un producto singular que un producto que se fabrique en serie (aunque algunos software tienen muchos miles de usuarios e, incluso, millones), ya que, si bien existe –y no siempre– producción en serie de copias del software, ésta es una actividad muy poco importante dentro del conjunto de su proceso productivo y relativamente sencilla. ¡La producción de software se parece a la construcción! Desde cierto punto de vista, la producción de software se parece a la construcción de viviendas o edificios industriales, por ejemplo, en el hecho de que cada producto es diferente y su elaboración se basa en un proyecto específico (en el caso de producción en serie, lo que se proyecta es un prototipo del producto, y no cada unidad que se produce).
© Editorial UOC
17
Capítulo I. Introducción a la...
Otras características del software son, como señala Pressman, que no se estropea por el uso ni por el paso del tiempo. Si finalmente se tiene que sustituir es porque se ha quedado tecnológicamente anticuado o inadaptado a nuevas necesidades o porque ha llegado a resultar demasiado caro mantenerlo.
1.2. La ingeniería del software
En general, a cada tipo de producto industrial corresponde un tipo de ingeniería, entendida como el conjunto de métodos, técnicas y herramientas que se utilizan tanto para desarrollar el producto (es decir, elaborar el proyecto o prototipo) como para fabricarlo (afinando más se puede decir que existen, pues, dos ingenierías para cada tipo de productos: la del producto y la del proceso). Una técnica es la manera preestablecida en la que se lleva a término un paso en la elaboración del producto, un método es una manera determinada de aplicar varias técnicas sucesivamente y una herramienta es un instrumento de cualquier tipo que se utiliza en la aplicación de una técnica. El software no es ninguna excepción a esta regla, y, por tanto, hay una ingeniería del software que comprende las técnicas, métodos y herramientas que se utilizan para producirlo. En el caso de la ingeniería del software no se suele hablar de ingeniería de proceso; quizá se podría pensar que es la que hace referencia a la programación en sentido estricto, pero cada vez es menos nítida la distinción entre la programación y las fases anteriores en el desarrollo de software.
1.3. Los grandes problemas de la ingeniería del software: la calidad y la productividad
A pesar de los grandes adelantos que ha habido en las técnicas de desarrollo de software durante los últimos treinta años, tanto la calidad del software como la productividad de su proceso de elaboración todavía no han alcanzado niveles
© Editorial UOC
18
Ingeniería del software
plenamente comparables con los de otras tecnologías más antiguas. Todo esto, combinado con un aumento realmente espectacular de la demanda de software, ha provocado lo que se ha denominado la crisis del software. En cuanto a la calidad, la causa principal de dificultades es la gran complejidad del software comparado con otros tipos de productos, que provoca, por ejemplo, que no sea posible, ni mucho menos, probar el funcionamento de un software en todas las combinaciones de condiciones que se pueden dar. Y eso ocurre en una época en la que se da cada vez más importancia a la calidad en todos los ámbitos, al considerarla un factor de competitividad dentro de unos mercados cada vez más saturados y, por tanto, más exigentes. No es extraño, pues, que el tema de la calidad (y dentro de éste, cuestiones como la garantía de calidad y las certificaciones oficiales de calidad) adquiera una importancia creciente dentro de la ingeniería del software. Por lo que respecta a la productividad, cabe decir para empezar que cualquier fabricación en serie tiene necesariamente una productividad mucho más elevada que la fabricación de un producto singular; pero, incluso, si la comparamos con otras ingenierías de producto singular, la productividad es claramente inferior. La complejidad del producto también puede ser una causa de este hecho, pero ciertamente no es la única. Un factor que tiene un peso realmente importante en la baja productividad es el hecho de que, a diferencia de las otras tecnologías, en un proyecto de software el desarrollo empieza tradicionalmente de cero (sólo recientemente se utilizan fragmentos de software “prefabricados”). El aprovechamiento de elementos en la fabricación en serie Cuando se diseña un nuevo modelo de coche, se incluyen desde el principio muchísimos elementos que ya existían y que, por tanto, no es necesario diseñar; no sólo elementos normalizados como tornillos y tuercas, sino también elementos más complejos como baterías e, incluso, motores o cajas de cambio completos. También en la construcción de edificios –una actividad que tiene más semejanzas con la producción de software, como se ha indicado– se utilizan muchos elementos estándares o prefabricados: tejas, vigas, ventanas, persianas, grifos, etc.
Por tanto, no es extraño que uno de los grandes retos, por el momento, de la ingeniería del software sea conseguir desarrollar fragmentos de software (de-
© Editorial UOC
19
Capítulo I. Introducción a la...
nominados componentes) que sean reutilizables, por un lado, y, por el otro, desarrollar software y reutilizar sus fragmentos (que seguramente estarán mejor probados que si se hicieran de nuevo, lo cual además mejoraría la calidad del software producido). Una de las vías mediante las cuales se pretende conseguir una cierta reutilización en el desarrollo orientado a objetos es especialmente con componentes; otras son los patrones de diseño (reutilización, si no de fragmentos de software, por lo menos de ideas o “recetas” para hacerlos) y los marcos o frameworks, que son estructuras formadas por sistemas de software a los cuales se pueden acoplar otros sistemas de software, sustituibles, para hacer funciones concretas.
2. El ciclo de vida del software
La producción de software es algo más que la programación; hay etapas que la preceden y otras que la siguen. El ciclo de vida del software está constituido por el conjunto de todas estas etapas. Los métodos y técnicas de la ingeniería del software se inscriben dentro del marco delimitado por el ciclo de vida del software, y, más concretamente, por las diferentes etapas que se distinguen. La misma existencia de distintos modelos del ciclo de vida del software hace comprender que no hay ninguno que sea ideal o que no tenga grandes limitaciones. Sin embargo, es indispensable que todo proyecto se desarrolle dentro del marco de un ciclo de vida claramente definido, si se quiere tener una mínima garantía de cumplimiento de los plazos, y respetar los límites de los recursos asignados. Además, la garantía de calidad y las certificaciones* de calidad también presuponen que el proceso de producción de software se desarrolle según un ciclo de vida con etapas bien definidas. *. Un ejemplo de certificación de calidad sería la ISO.
© Editorial UOC
20
Ingeniería del software
2.1. El ciclo de vida clásico
La figura siguiente nos muestra las etapas previstas en una cierta versión del ciclo de vida clásico.
A veces, el ciclo de vida clásico también se denomina ciclo de vida en cascada, lo cual quiere decir que en cada etapa se obtienen unos documentos (en inglés, deliverables) que son las bases de partida de la etapa siguiente –que, por tanto, no puede comenzar antes de que haya terminado la anterior– y nunca se regresa a etapas pasadas.
2.1.1. Etapas
La primera etapa se denomina análisis previo y también análisis de sistemas o ingeniería de sistemas. En esta etapa se definen los grandes rasgos del sistema de software que tendrá que dar soporte informático a unas actividades determinadas de unos ciertos usuarios dentro del marco más general de la actividad de la empresa u organización.
© Editorial UOC
21
Capítulo I. Introducción a la...
Además, este sistema tendrá que funcionar en un entorno de hardware y red determinado, que será necesario indicar, y quizá también tendrá que intercambiar información con otro software o compartir una base de datos. Estos hechos constituyen otros aspectos del entorno del futuro software de los cuales se tendrá que dejar constancia. Hay que tener en cuenta los recursos necesarios para el desarrollo del software y los condicionamientos temporales, especialmente los plazos impuestos desde fuera del proyecto, que a menudo están determinados por los hechos que han causado las necesidades de información que tiene que satisfacer dicho software, y también restricciones eventuales y condiciones adicionales que sea necesario respetar; y, en función de todo esto, se evalúa la viabilidad técnica, económica y legal del proyecto de desarrollo de dicho software. El documento que resulta de esta etapa se denomina Especificación del sistema, y sirve de base para tomar la decisión definitiva sobre la continuación del proyecto. La segunda etapa es el análisis de requisitos o simplemente análisis. Su objetivo es definir con detalle las necesidades de información que tendrá que resolver el software, sin tener en cuenta, por el momento, los medios técnicos con los que se tendrá que llevar a término el desarrollo del software. Como el lenguaje de programación, el gestor de bases de datos, los componentes que se pueden reutilizar, etc. En esta etapa detallamos los requisitos de la etapa anterior; ahora sólo pensamos en el software que es necesario desarrollar y sus interfaces con el entorno. La figura responsable del análisis –el analista, que puede ser un informático o un usuario– debe tener o adquirir conocimientos generales sobre el dominio de la aplicación y obtener información de los usuarios y de otras fuentes que le permita hacerse una idea precisa de las funciones, y de los requisitos en general, del futuro software. Con esta información se redacta el documento que llamaremos Especificación de requisitos, que tiene una doble función: especificar qué debe hacer el software, con la suficiente precisión para que se pueda desarrollar, y servir de base para un contrato, explícito o no, entre el equipo de desarrollo del software y sus futuros usuarios. El diseño es la etapa siguiente. Si el análisis especifica el problema o “qué tiene que hacer el software”, el diseño especifica una solución a este problema o “cómo el software tiene que hacer su función”.
© Editorial UOC
22
Ingeniería del software
Del software, hay que diseñar varios aspectos diferenciados: su arquitectura general, las estructuras de datos (base de datos, etc.), la especificación de cada programa y las interfaces con el usuario, y se tiene que llevar a cabo de manera que, a partir de todo esto, se pueda codificar el software, de una manera parecida a la construcción de un edificio o de una máquina a partir de unos planos. El documento resultante es la Especificación del diseño. La etapa de diseño es el mejor momento para elaborar la Especificación de la prueba, que describe con qué datos se tiene que probar cada programa o grupo de programas y cuáles son los resultados esperados en cada caso. La programación o codificación, que es la cuarta etapa, consiste en traducir el diseño a código procesable por el ordenador. Es en esta etapa donde se le da forma real al software, es en realidad cuando se elabora. El entregable que se genera en esta etapa es el programa propiamente, con todas sus funcionalidades y componentes. La prueba es la última etapa del desarrollo del software y la penúltima del modelo de ciclo de vida del software que hemos considerado. La etapa de prueba consiste en probar el software desde distintos puntos de vista de una manera planificada y, naturalmente, localizar y corregir dentro del software y su documentación los errores que se detecten. La prueba se lleva a término en las dos fases siguientes: 1) En la primera se hacen pruebas, primero para cada uno de los programas por separado y, después, por grupos de programas directamente relacionados, y se aplica la especificación de la prueba que hemos mencionado con anterioridad. 2) En la segunda fase se comprueba que el conjunto de programas dé los resultados que se esperan y que lo haga con el rendimiento deseado. El primer equipo de desarrollo hace la última fase de la prueba y, si los resultados son satisfactorios, se entrega el software al cliente, el cual puede hacer una prueba parecida por su cuenta y con sus datos, con la finalidad de decidir si acepta el software. Con la aceptación por parte del cliente se da por terminado el desarrollo. La última etapa del ciclo de vida es el mantenimiento o, si se prefiere, explotación, del software, ya que siempre que se utilice el software habrá que mantenerlo, es decir, hacer cambios –pequeños o grandes– para corregir errores, mejorar
© Editorial UOC
23
Capítulo I. Introducción a la...
las funciones o la eficiencia, o adaptarlo a un nuevo hardware o a cambios en las necesidades de información. Puesto que un software puede estar en explotación diez años o más, a menudo el coste total del mantenimiento durante la vida del software es de dos a cinco veces mayor que el coste de desarrollo.
2.1.2. El caso de lenguajes de cuarta generación Los lenguajes –o más bien entornos de programación– de cuarta generación son de muy alto nivel (en el sentido de que a menudo una sola de sus instrucciones equivale a muchas instrucciones del lenguaje ensamblador) y en gran parte son no procedimentales y están integrados en un gestor de bases de datos relacionales. Incluyen herramientas de dibujo de pantallas, generación de listados y en ocasiones salidas gráficas y hoja de cálculo. Algunos pueden generar código en un lenguaje de tercera generación. Para aplicaciones sencillas, se puede pasar directamente de los requisitos a la codificación, pero en proyectos complejos es necesario llevar a cabo una etapa de diseño, aunque simplificada.
2.2. Los ciclos de vida iterativos e incrementales El ciclo de vida en cascada ha sido muy criticado y se han propuesto algunos modelos alternativos.
2.2.1. Inconvenientes del modelo de ciclo de vida en cascada El inconveniente del modelo de ciclo de vida en cascada es que no es realista. Como se ha visto, el modelo de ciclo de vida en cascada comporta que las sucesivas etapas del desarrollo se hacen de manera lineal, de forma que una fase no comienza mientras no se haya acabado la anterior, y no se vuelve nunca atrás. También queda implícito en el modelo que, cuando se acaba una fase, se s abe al menos aproximadamente qué porcentaje del proyecto queda por hacer, ya que
© Editorial UOC
24
Ingeniería del software
si el análisis se ha completado y su resultado es cien por cien fijo, se puede saber con cierta precisión la duración del diseño e, incluso, de la programación. Ahora bien, en la realidad es posible que la especificación del sistema sea fiable en lo que respecta a las funciones, ya que no se espera que se describan punto por punto. Sin embargo, precisamente por esto último, el coste y la duración del proyecto se han calculado sobre una base muy poco sólida y tienen un gran margen de error. No obstante, el problema más grave se presenta en el análisis de requisitos, por el hecho de que éstos casi siempre son incompletos al principio o cambian antes de que se haya acabado de construir el software, y a menudo suceden ambas cosas a la vez. Y si la especificación de requisitos es incompleta e insegura, es obvio que el diseño y la programación tendrán problemas y, sobre todo, retrasos y aumentos de coste importantes para el trabajo no previsto que se deberá hacer y también para el que será necesario rehacer. Existen dos razones por las cuales es prácticamente imposible elaborar unos requisitos completos y estables en el primer intento: a) En primer lugar, es difícil encontrar un conjunto de futuros usuarios que conozcan lo suficiente el entorno en el que se debe utilizar el software, que hayan reflexionado lo suficiente sobre lo que quieren conseguir y que, además, se pongan de acuerdo. b) En segundo lugar, porque el trabajo de consolidación de las peticiones de estos usuarios nunca será perfecto. En cualquier caso, tenemos que contar con el hecho de que, una vez terminada oficialmente la etapa de análisis y comenzada la de diseño, todavía surgirán requisitos nuevos y cambios en los ya existentes. ¿Qué se puede hacer, entonces? Parece que la opción más razonable sea estudiar a fondo una pequeña parte de los requisitos que tenga una cierta autonomía, y diseñarla, programarla y probarla, y una vez que el cliente la haya dado por buena, hacer lo mismo con otra parte, y otra. Si partimos de un software ya construido en parte, se puede esperar que la idea que nos hacemos de los requisitos restantes pueda ser cada vez más precisa y que también obtengamos una estimación cada vez más segura del coste y de la duración del proyecto completo; esto es lo que denominamos ciclo de vida iterativo e incremental (iterativo por-
© Editorial UOC
25
Capítulo I. Introducción a la...
que se repite dentro de un mismo proyecto e incremental porque procede por partes). Y se tendrá que considerar normal que, a veces, cuando se construya una parte, se vea que es necesario modificar una hecha con anterioridad. La necesidad de estimar el coste y los plazos Los inconvenientes del modelo del ciclo de vida clásico mencionados en este subapartado no quieren decir que no pueda haber plazo o límite de coste para un proyecto de desarrollo de software; simplemente, se debe reconocer que no es realista creer que se pueda fijar de forma exacta la funcionalidad, el coste y la duración del proyecto, todo a la vez. Si el software tiene que funcionar en una fecha determinada y no se puede aumentar el gasto en personal, será necesario estar dispuesto a aceptar que el software no realice todas las funciones deseadas; si la funcionalidad y la fecha de entrega del programa son innegociables, se tendrá que aumentar el número de programadores o analistas. Y esto no supone ninguna renuncia en relación con los resultados que se alcanzaban hasta ahora, porque en la práctica muy pocos eran los proyectos en los que no se producían desviaciones en cuanto a la funcionalidad, presupuesto o plazo, sino en varias de estas cosas al mismo tiempo.
Por tanto, el modelo de ciclo de vida en cascada puede ser válido si se aplica de manera que cada etapa, del análisis de requisitos a la prueba, no prevea todo el conjunto del software, sino sólo una parte cada vez; entonces tendríamos un ciclo de vida iterativo e incremental basado en el ciclo de vida en cascada.
2.2.2. El ciclo de vida con prototipos
Para ayudar a concretar los requisitos, se puede recurrir a construir un prototipo del software. Un prototipo es un software provisional, construido con herramientas y técnicas que dan prioridad a la rapidez y a la facilidad de modificación antes que a la eficiencia en el funcionamiento, que sólo tiene que servir para que los usuarios puedan ver cómo sería el contenido o la apariencia de los resultados de algunas de las funciones del futuro software. Un prototipo sirve para que los usuarios puedan confirmar que lo que se les muestra, efectivamente, es lo que necesitan o bien lo puedan pedir por comparación, y entonces se prepara una nueva versión del prototipo teniendo en cuen-
© Editorial UOC
26
Ingeniería del software
ta las indicaciones de los usuarios y se les enseña otra vez. En el momento en que el prototipo ha permitido concretar y confirmar los requisitos, se puede comenzar un desarrollo según el ciclo de vida en cascada, en este caso, no obstante, partiendo de una base mucho más sólida. Características del ciclo de vida con prototipos El ciclo de vida con prototipos no se puede considerar plenamente un ciclo de vida iterativo e incremental, ya que sólo el prototipo se elabora de manera iterativa, y no necesariamente incremental. Sin embargo, es un modelo de ciclo de vida que puede ser adecuado en algunos casos, en especial cuando basta con prototipar un número reducido de funciones para que las otras sean bastante parecidas a éstas de forma que las conclusiones a las que se llegue con el prototipo también les sean aplicables.
2.2.3. La programación exploratoria La programación exploratoria consiste en elaborar una primera versión del software, o de una parte de éste, enseñarla a los usuarios para que la critiquen y, a continuación, hacerle los cambios que éstos sugieran, proceso que se repetirá tantas veces como sea necesario. La diferencia principal con respecto a los prototipos es que aquí el software es real desde el principio. Características de la programación exploratoria La programación exploratoria se puede considerar un ciclo de vida iterativo, pero no incremental, ya que el software está completo desde la primera versión. Como consecuencia de las numerosas modificaciones que sufre, la calidad del software desarrollado de esta manera y de su documentación tiende a ser deficiente, como la de un software que haya experimentado un mantenimiento largo e intenso.
2.2.4. El ciclo de vida del Rational Unified Process La empresa Rational Software ha propuesto este ciclo de vida como marco para el desarrollo de software que utiliza sus herramientas. Es claramente un ciclo de vida iterativo e incremental.
© Editorial UOC
27
Capítulo I. Introducción a la...
Se distinguen estas cuatro etapas (denominadas fases): 1) Inicio Se establece la justificación económica del software y se delimita el alcance del proyecto. 2) Elaboración Se estudia el dominio del problema, o simplemente dominio (parte de la actividad de la empresa dentro de la cual se utilizará el software) y se tienen en cuenta muchas de las necesidades de información y eventuales requisitos no funcionales y restricciones, se establece la arquitectura general del software y se realiza una planificación del proyecto. 3) Construcción Se desarrolla todo el producto de forma iterativa e incremental, se tienen en cuenta todas las necesidades de información que debe satisfacer y se desarrolla la arquitectura obtenida en la fase anterior. 4) Transición Comprende la entrega del producto al cliente y el comienzo de su utilización; aunque es posible que sea necesario hacer retoques en el software y añadir nuevas funciones como consecuencia de errores detectados o de requisitos que se habían pasado por alto hasta el momento. En cada una de estas fases se llevan a cabo (en diferentes proporciones) los siguientes componentes de proceso: • recogida de requisitos (requirement capture), • análisis y diseño, • realización (implementation), • prueba (test ). Cada unidad en la que se ejecutan pocos o muchos de los componentes de proceso es una iteración, y se aplica a un nuevo fragmento de software. Todas las fases tienen iteraciones.
© Editorial UOC
28
Ingeniería del software
3. Desarrollo estructurado y desarrollo orientado a objetos
Los métodos de desarrollo de software más utilizados hasta ahora pertenecen a dos grandes grupos: los métodos estructurados y los métodos orientados a objetos.
3.1. Los métodos estructurados
Los métodos estructurados provienen de la programación estructurada y se utilizan técnicas no muy integradas entre sí. Los métodos estructurados tienen, asimismo, estas características: • La especificación de los procesos y la de las estructuras de datos generalmente quedan bastante diferenciadas, y hay métodos que ponen más énfasis en aquéllos o en éstos. • Muchas de sus técnicas o bien pasan de lo general a lo particular (técnicas topdown) o bien a la inversa (técnicas bottom-up). Técnicas más utilizadas para los métodos estructurados Las técnicas más usadas en los métodos estructurados son seguramente los diagramas de entidad-relación y de flujo de datos, con sus variantes. Los primeros se refieren a los datos y los segundos, a los procesos.
3.2. Los métodos orientados a objetos
Si bien los métodos estructurados continúan siendo muy utilizados, los denominados métodos orientados a objetos ganan terreno rápidamente. Si los métodos estructurados de desarrollo de software tienen su origen en la programación estructurada, los métodos orientados a objetos tienen sus raíces en la programación orientada a objetos. Es lógico que haya sucedido así en los dos casos: una nueva técnica de programar exige una nueva manera de diseñar los programas adaptada a las carac-
© Editorial UOC
29
Capítulo I. Introducción a la...
terísticas de la programación, y un nuevo método de diseño hace deseable un nuevo método de análisis de requisitos que tenga la misma orientación que el diseño, con la finalidad de evitar que el paso del análisis de requisitos al diseño implique un cambio de modelo que inevitablemente comportaría un trabajo adicional y un mayor riesgo de errores. De la misma manera que la programación orientada a objetos gira en torno al concepto de clase, también lo hacen el análisis de requisitos y el diseño. Por esta razón, el diagrama básico de estos métodos, el diagrama de clases y objetos, se utiliza tanto en el análisis como en el diseño; además, muchas de las clases descritas en el análisis de requisitos se implementan en los programas pasando por el diseño, lo cual hace que el paso del análisis de requisitos al diseño sea más suave que en los métodos estructurados y también más sencillo y rápido. Puesto que dentro de una clase hay a la vez atributos y operaciones, es decir, datos y procesos, en el desarrollo orientado a objetos a medida que se definen e implementan clases se avanza al mismo tiempo en estas dos dimensiones. El desarrollo no procede ni de manera top-down ni bottom-up, sino que, más bien, se construyen grupos de clases interrelacionadas, a menudo por niveles: clases que gestionan la presentación de la información, o bien las entradas por pantalla, o bien las lecturas y grabaciones de la base de datos, o bien los algoritmos principales del software; o bien proceden según un ciclo de vida incremental, tal como hemos visto. Cabe añadir que el desarrollo orientado a objetos, además de introducir técnicas nuevas, también aprovecha algunas técnicas y conceptos del desarrollo estructurado, como el diagrama de estados y transiciones, según veremos. Hay dos características del desarrollo orientado a objetos que probablemente han favorecido de m anera decisiva su expansión hasta ahora y también con toda probabilidad la continuarán favoreciendo: • Parece que permite –por primera vez en la historia de la tecnología del software– la reutilización de software en un grado significativo, en forma de clases implementadas, lo cual podría significar una vía para solucionar, aunque sólo sea en parte, los problemas de productividad y calidad descritos en apartados anteriores. •
Su relativa simplicidad facilita el desarrollo de herramientas informáticas de ayuda al desarrollo; este factor podría ser potenciado por el hecho de que en
© Editorial UOC
30
Ingeniería del software
estos últimos años ha aparecido una notación orientada a objetos muy ampliamente aceptada, el UML.
3.3. Los métodos formales Los denominados métodos formales parten de una especificación de las necesidades de información en términos de un modelo matemático riguroso, del cual se podría deducir el programa que les satisfaga. También permitían demostrar matemáticamente que un programa es correcto en el sentido de que se ajusta a aquellas necesidades. Aunque tendrían que permitir eliminar las ambigüedades y carencias de los métodos no tan rigurosos, su utilización directa en el desarrollo de software para usos reales es poco frecuente en la actualidad, sin duda debido a la gran complejidad que tendría un modelado tan detallado y formalizado en casos reales. Algunos de los lenguajes de especificación formal más conocidos son Z, VDM, CSP y LARCH.
4. Las herramientas CASE
CASE significa Computer-Aided Software Engineering. Las herramientas CASE son software de apoyo al desarrollo, mantenimiento y documentación informatizados de software. De esta definición generalmente se excluyen las herramientas que tienen una de las funciones siguientes: 1) o bien no tienen sólo esta finalidad (herramientas de tratamiento de texto, de hoja de cálculo, de dibujo en general, de planificación de proyectos de cualquier ingeniería), ya que propiamente pertenecen a otros ámbitos; 2) o bien se utilizan para codificar el software (compiladores, entornos de cuarta generación, editores ordinarios de programas, etc.), ya que siempre están presentes, incluso cuando el desarrollo de software se hace de la manera más manual posible.
© Editorial UOC
31
Capítulo I. Introducción a la...
Quedan, pues, principalmente las herramientas que ayudan a aplicar técnicas concretas de desarrollo y mantenimiento de software y por eso gestionan información sobre los elementos y conceptos que se utilizan en los métodos de desarrollo, como las siguientes: • Las herramientas diagramáticas, las cuales, a diferencia de las de dibujo, reconocen que un determinado símbolo es una clase y no simplemente un rectángulo. Estas herramientas también acostumbran a aceptar documentación textual sobre aquellos elementos. • Las herramientas de gestión de la prueba y de gestión de la calidad en general. • Las herramientas de gestión de cambios, etc. Herramientas UpperCASE y LowerCASE A veces se distingue entre herramientas UpperCASE, que son las de análisis y diseño, y LowerCASE, que se usan durante la programación y la prueba. La importancia de la integración de las herramientas Es conveniente que las herramientas que dan apoyo a diferentes técnicas utilizadas dentro del mismo método estén integradas, en el sentido de que si hay un tipo de elemento que es común a dos técnicas, sea compartido por las dos herramientas respectivas, de manera que sólo sea necesario describirlo una vez y que todos los cambios que se realicen después en esta descripción lleguen a las dos.
La expansión del uso de herramientas CASE en el método estructurado se frenó a causa de la diversidad y de la falta de estandarización de las técnicas que se utilizan; en los métodos orientados a objetos, en cambio, actualmente la situación es la contraria: por un lado, algunos diagramas sirven tanto para el análisis como para el diseño, y por el otro, se ha producido una estandarización de las técnicas y notaciones en el modelo conocido como UML que ha hecho que en el poco tiempo transcurrido desde su publicación haya aparecido un número importante de conjuntos integrados de herramientas CASE basadas en él. Este soporte informatizado, amplio y creciente, en el desarrollo de software orientado a objetos sin duda reforzará la mejora de la calidad y la productividad en el de-
© Editorial UOC
32
Ingeniería del software
sarrollo de software que, tal como hemos visto, la tecnología orientada a objetos tiene que fomentar.
5. El OMG y el UML
Para el desarrollo orientado a objetos utilizaremos el modelo denominado UML, del cual actualmente es responsable la organización llamada OMG.
5.1. El Object Management Group (OMG)
El Object Management Group (OMG), creado en 1989, es una organización no lucrativa en la cual participan más de ochocientas grandes empresas de software, de hardware, usuarias y consultoras, y tiene la finalidad de fomentar el uso de la tecnología de objetos e impulsar la introducción de software orientado a objetos que ofrezca reusabilidad, portabilidad e interoperabilidad en entornos distribuidos heterogéneos. El medio con que el OMG intenta conseguir sus objetivos es la elaboración de estándares, para los cuales acepta propuestas. En cambio, no produce software ni elabora especificaciones de implementación o funcionalidad. El otro estándar del OMG Además del UML, otro estándar que ha elaborado el OMG es CORBA, sobre objetos distribuidos, cuyas implementaciones tienen una expansión rápida.
5.2. Unified Modeling Language (UML)
El Unified Modeling Language (UML) es un modelo para la construcción de software orientado a objetos que ha sido propuesto como estándar de ISO por el
© Editorial UOC
33
Capítulo I. Introducción a la...
OMG. Consta de un conjunto de tipos de diagramas interrelacionados, dentro de los cuales se utilizan elementos del modelo, que sirven parar describir distintos aspectos de la estructura y la dinámica del software. UML es el resultado de una cierta unificación de los modelos utilizados en tres métodos preexistentes de desarrollo de software orientado a objetos hechos por sus autores en colaboración. Estos métodos son los siguientes: • el método de Grady Booch; • el OMT, de Jim Rumbaugh y otros; • el OOSE, de Ivar Jacobson. Además, se encuentran conceptos aportados por muchos otros autores, entre ellos Peter Coad, Edward Yourdon, James Odell y Bertrand Meyer. Evolución del modelo UML Los primeros pasos hacia el modelo unificado se dieron en el año 1994, cuando Booch y Rumbaugh, trabajando en Rational Software Corporation, comenzaron la unificación de los modelos respectivos, y en octubre de 1995 se publicó la versión provisional 0.8 del entonces denominado Unified Method. El mismo año, Jacobson se incorporó con su empresa al equipo mencionado y a Rational y, como resultado del trabajo de los tres autores, en 1996 salieron las versiones 0.9 y 0.91 del UML. El OMG emitió en aquella época una Request For Proposal, para un modelo de este tipo, y entonces Rational, para responderle, constituyó un consorcio con otras organizaciones, con el resultado de que en enero de 1997 se presentó en la OMG la versión 1.0 del UML. Otras empresas que habían presentado también respuestas de manera independiente se añadieron al consorcio y se publicó la versión 1.1, que fue aceptada por el OMG en noviembre de 1997 (hubo otra propuesta, la del modelo OML, que tenía y todavía tiene un número importante de partidarios). El OMG encargó una revisión, cuyo resultado fue una versión 1.2, no publicada, y la versión 1.3, ya publicada como estándar. La versión 1.4 se publicó oficialmente en septiembre de 2001.
Con el UML se ha llegado a un modelo orientado a objetos único como modelo oficial, pero eso no quiere decir que se haya alcanzado un método único de desarrollo orientado a objetos; la verdad es que por el momento parece que falta bastante para llegar al mismo, si es que alguna vez se consigue. Es decir,que
© Editorial UOC
34
Ingeniería del software
lo que se ha conseguido es que haya unos diagramas que todos los desarrolladores de software orientado a objetos entenderán y harán de la misma manera, lo cual supone un adelanto realmente importante con respecto a la situación anterior en la que cada método tenía su notación gráfica; pero, incluso así, continúa siendo posible que existan métodos diferentes que utilicen el UML y que, por ejemplo, se valgan de los mismos diagramas en orden diferente o dentro de modelos de ciclo de vida distintos.
© Editorial UOC
35
Capítulo I. Introducción a la...
Conclusiones
Se ha concretado qué se entiende por software en esta obra, se ha indicado por qué se puede considerar un producto industrial y, como consecuencia, por qué tiene sentido hablar de una ingeniería del software, y también hemos entrado en contacto con los dos grandes problemas que han afectado tradicionalmente al desarrollo de software: las carencias referidas a la productividad y calidad. Si entramos dentro del proceso de elaboración del software, hemos visto el concepto de ciclo de vida y sus dos grandes modelos –el ciclo de vida en cascada o clásico y los ciclos de vida iterativos e incrementales–, más dos modalidades intermedias –el desarrollo con prototipos y la programación exploratoria. Como ciclos concretos, hemos indicado de una manera más o menos detallada el ciclo de vida del Rational Unified Process, como representante de las tendencias actuales en lo que se refiere a ciclos iterativos e incrementales, y el ciclo de vida clásico, cuyo interés radica, además de en su importancia histórica, en el hecho de que algunos de sus conceptos continúan siendo válidos todavía. A continuación, se han presentado las tres grandes familias de métodos de desarrollo de software: las dos más utilizadas en entornos reales, que son los métodos estructurados –más tradicionales– y los métodos orientados a objetos –en plena expansión–, sin menospreciar los métodos formales, interesantes por su gran rigor teórico. Después de hablar de técnicas, es lógico referirse a las herramientas que éstas emplean; por eso hemos visto el concepto de herramientas CASE y nos hemos informado de su situación actual y de la evolución previsible de su papel. Puesto que para estudiar el análisis y diseño orientados a objetos –tema esencial de esta obra– utilizaremos los conceptos y la notación del UML, se ha expuesto el origen de este modelo y el cometido de la organización que se responsabiliza del mismo, la OMG.
© Editorial UOC
37
Capítulo II. UML (I): el modelo estático
Capítulo II
UML (I): el modelo estático
Como sabemos, para el análisis y el diseño orientados a objetos utilizaremos los conceptos y las notaciones –esencialmente gráficas– del UML. El UML comprende un cierto número de diagramas interrelacionados mediante conceptos comunes. Sólo para describirlos, los consideraremos agrupados en tres modelos: Estático
describe la estructura de clases y objetos.
Dinámico
(o modelo de comportamiento), describe las interacciones entre los objetos dentro del software.
Implementación
describe la estructura del software en cuanto a los componentes de que consta y su ubicación.
En este capítulo veremos el modelo estático, que consta, por una parte, de clases y objetos, y por la otra, de relaciones de diferentes tipos entre clases y entre objetos. En capítulos posteriores trataremos el resto de los modelos y la utilización del UML en el análisis y en el diseño.
1. Concepto de modelo estático y diagrama de clases
El modelo estático del UML es aquél en el que se describen las clases y los objetos. Se denomina estático porque muestra todas las relaciones posibles a lo largo del tiempo, no las que son válidas en un cierto momento.
© Editorial UOC
38
Ingeniería del software
Ejemplo de modelo estático Un diagrama estático nos puede mostrar que cada profesor tiene, al menos, una asignatura, y que cada asignatura tiene, al menos, un profesor, pero no nos dice qué asignaturas tiene un profesor concreto.
Este modelo consta de los dos diagramas siguientes: • Diagrama de clases, que puede contener clases y objetos y relaciones entre éstos, y que se hace siempre. • Diagrama de objetos, que sólo contiene objetos y relaciones entre éstos, y que es opcional, ya que se utiliza principalmente para realizar ejemplos del diagrama de clases con objetos concretos de las mismas. Un diagrama de clases muestra la estructura estática de las clases en un dominio (porción del mundo real considerada por una aplicación); se muestran las clases y las relaciones entre éstas, que pueden ser de herencia, asociación, agregación o uso. Uso del modelo estático El modelo estático se utiliza en todas las etapas del ciclo de vida; en las diferentes etapas se documentan diferentes tipos de objetos. En el análisis se consideran objetos del mundo del usuario (por ejemplo, artículos, facturas, clientes, etc.) y en el diseño, en cambio, se consideran objetos de la tecnología informática: pantallas, gestores de disco, etc.
El modelo estático pretende ser independiente del lenguaje de programación, pero, sin embargo, si se sabe cuál será, es conveniente no utilizarlo en el análisis de conceptos que sabemos que dicho lenguaje no soporta, si queremos ahorrarnos muchos cambios cuando lleguemos al diseño. También se deberá tener en cuenta que, cuando el UML permite describir elementos incompatibles con un lenguaje determinado, raramente la herramienta CASE nos lo impedirá; por lo tanto, será responsabilidad del diseñador del software evitar caer en la utilización de conceptos no soportados por el lenguaje de programación.
© Editorial UOC
39
Capítulo II. UML (I): el modelo estático
Relaciones en los lenguajes de programación Los lenguajes de programación soportan las relaciones de herencia, pero no distinguen entre los otros tres tipos de relaciones que existen; por tanto, al pasar del diseño a la programación, estos tipos se tendrán que transformar.
También puede suceder lo contrario; es decir, que se quieran modelar elementos que la herramienta CASE no soporta, porque UML no los prevé, o por otros motivos; entonces se tendrán que documentar estos aspectos mediante comentarios libres, que permiten todas las herramientas. Algunas herramientas permiten que el usuario defina extensiones, pero si una empresa utiliza esta posibilidad, los diagramas generados no serán transportables a otras empresas.
2. Clasificadores
El clasificador es la entidad básica del modelo estático. Un clasificador es más general que una clase; es un conjunto cuyos elementos se denominan instancias. El clasificador en sí mismo no tiene símbolo gráfico, sino que lo tienen sus estereotipos: • Clase: El concepto de clase es el que ya conocemos de la programación orientada a objetos, y sus instancias son los objetos, que tienen identidad, en el sentido de que incluso dos objetos que coinciden en el valor de todos sus atributos son objetos diferentes si se han creado como tales. • Tipo de dato: Por tipo de dato entendemos un tipo base ofrecido por algún lenguaje de programación o construido por el programador; tiene operaciones asociadas igual que las clases, pero sus instancias, a diferencia de los objetos, no tienen identidad. • Interfaz: Una interfaz sólo describe las operaciones de una clase que son visibles desde otras clases; se dice que dicha clase implementa la interfaz correspondiente.
© Editorial UOC
40
Ingeniería del software
Estereotipo Un estereotipo de un elemento del UML es una variante más restrictiva de dicho elemento; hay estereotipos que forman parte del UML, y también se pueden encontrar estereotipos definidos referidos al diagrama, que son un instrumento para extender el UML, pero así se pierde portabilidad.
La utilidad del concepto de clasificador radica en el hecho de que los estereotipos mencionados tienen mucho en común, por lo que es suficiente con realizar la indicación una vez en el clasificador. La notación gráfica simplificada es la misma para los tres: un rectángulo. Todos los clasificadores deben tener un nombre. En un clasificador se puede indicar la palabra clave del estereotipo (entre comillas latinas, «»). Cuando no se indique ningún estereotipo, se tratará de una clase.
3. Paquetes
Un paquete o package es sólo una “caja” que contiene elementos, como clasificadores, objetos u otros paquetes, así como otras entidades que veremos más adelante, como los casos de uso. Paquetes en JAVA Por la definición que ofrecemos de paquete, podemos ver que el concepto de paquete en el UML es diferente –y más amplio– que en Java.
© Editorial UOC
41
Capítulo II. UML (I): el modelo estático
Gráficamente, un paquete se representa así:
Todas las aplicaciones deben tener, por lo menos, un paquete que normalmente se denomina raíz. Cada elemento de un paquete tiene visibilidad, es decir, puede ser reconocido o bien desde todos los otros paquetes, o bien sólo desde algunos.
Ejemplo de paquetes Éstas son dos maneras de representar el mismo paquete:
En la primera, se pueden incluir dentro del símbolo del paquete los símbolos de los elementos que contiene; la segunda, simplificada, es más adecuada para representar referencias al paquete (desde otros paquetes, por ejemplo).
Se pueden establecer los siguientes tipos de relaciones entre paquetes: • De especialización. Si un paquete A hereda de otro B todos los elementos de B, son casos más restrictivos de elementos de A. • De inclusión. Si el paquete A incluye el B, todos los elementos de B están también en A.
© Editorial UOC
42
Ingeniería del software
• De importación. Desde el paquete que importa se reconocen los nombres de los elementos del otro paquete visibles desde el exterior. Ejemplo Por ejemplo, públicos en el sentido de Java.
• De acceso. No sólo se reconocen los nombres de los elementos, sino que, además, se pueden utilizar. Ejemplo de relaciones entre paquetes En la representación gráfica, el paquete Diagramas que vemos a continuación importa del paquete Figuras, y el paquete Diagramas de UML hereda del paquete Diagramas; una relación de acceso se representaría con la palabra clave access.
© Editorial UOC
43
Capítulo II. UML (I): el modelo estático
4. Clase y conceptos afines
Sobre la programación orientada a objetos sabemos que una clase describe un conjunto de objetos en el cual todos tienen los mismos atributos y las mismas operaciones. Los atributos y operaciones pueden ser de instancia, es decir, vinculados a objetos individuales, y de clase, que no están relacionados con ningún objeto en particular de la clase. Este mismo es el concepto de clase en el UML. En principio, cada clase es visible (es decir, reconocida) dentro del paquete donde se ha declarado, y su nombre no puede estar repetido en éste, pero desde un paquete se reconocen los nombres de clases –y elementos en general– de otro paquete del que se importa, en el sentido indicado con anterioridad; el nombre de la clase tiene que estar calificado por el del paquete, así Paquete : Clase.
4.1. Representación ampliada de las clases
Puesto que una clase es un clasificador, se puede utilizar como símbolo de la clase un simple rectángulo con el nombre. Sin embargo, dado que una clase consiste en un encapsulado de unos atributos y unas operaciones, también se da una representación gráfica más detallada por medio de un rectángulo dividido en los tres compartimentos siguientes: • El primer compartimento contiene el nombre de la clase. • El segundo compartimento contiene la lista de los atributos. • El tercer compartimento corresponde a los servicios de la clase. Se ha de tener en cuenta que como sinónimos de operación se utilizan a menudo método y servicio; pero en UML, el término servicio no se usa, y por método se entiende la implementación de una operación.
El usuario puede crear otros compartimentos, además de los tres obligatorios, para dar información adicional como excepciones, requisitos, etc.
© Editorial UOC
44
Ingeniería del software
4.1.1. El compartimento del nombre
En la parte superior del compartimento de la clase se puede indicar un estereotipo. Algunos estereotipos forman parte del UML –como metaclass, del que se hablará más adelante–, y se pueden definir mediante un proyecto concreto, por ejemplo. Justo debajo se encuentra el nombre de la clase. Se recomienda que sea un sustantivo en singular que a veces puede tener una segunda palabra que la califique. También es recomendable que comience por mayúscula. Debajo del nombre se pueden encontrar comentarios optativos entre llaves ({}) denominados cadenas de caracteres de propiedades (property strings) o valores etiquetados (tagged values)*; los puntos suspensivos que se pueden hallar al final de uno de los apartados indican que hay más elementos, pero que no se ven. La property string “abstract” denota una clase abstracta. El nombre de clases Los nombres de las clases tienen que estar bien pensados. La posibilidad de reutilización depende en gran medida de ello, porque cuando queramos reutilizar una clase de una librería que tenga centenares de nombres, la única pista que tendremos es el nombre, y si no se le dio un nombre adecuado, será muy difícil de encontrar. Un atributo de clase es lo mismo que un atributo static de Java y una variable de clase de Smalltalk y C++. Ejemplo de clase sólo con el compartimento del nombre En la figura siguiente, el estereotipo análisis podría indicar que la clase Rectangulo se ha identificado en la etapa de análisis. *. Formato de los comentarios Property strings y tagged values tienen la forma nombre = valor; en el caso de propiedades booleanas, el nombre solo ya indica la presencia de la propiedad.
© Editorial UOC
45
Capítulo II. UML (I): el modelo estático
4.1.2. Especificación de los atributos Cada atributo tiene un nombre o identificador y un tipo. Este último puede ser un tipo simple del lenguaje de programación (por lo menos, durante el diseño y la programación, porque durante el análisis puede ser que las clases se describan sin pensar en ningún lenguaje de programación en concreto) como entero o carácter, o bien un tipo complejo, como una lista de enteros, o también una clase ya definida. Un atributo, sea de instancia o de clase, se define de la siguiente forma: visibilidad nombre ‘:’ expresión-de-tipo ?=’ valor-inicial ‘{’ property string ‘}’ Se indica que un atributo es atributo de clase* subrayando su definición. La visibilidad de un atributo** indica hasta qué punto las operaciones de otras clases pueden acceder al atributo, y se indica mediante los siguientes símbolos. • Público: “+” • Protegido: “#” • Privado: “-” • Dentro del paquete: “ ” También tienen visibilidad otros elementos del modelo estático, como las operaciones y los extremos de asociación. *. Atributo de clase. Un atributo de clase es lo mismo que un atributo static de Java y una variable de clase de Smalltalk y C++. **. La visibilidad. En el UML no hay definiciones del significado de estas opciones de visibilidad, sino que se dejan para los lenguajes de programación; si algún lenguaje incluye más tipos de visibilidad, también se podrán indicar aquí.
© Editorial UOC
46
Ingeniería del software
En el lugar de los atributos, se pueden utilizar property strings, que son, respectivamente, public, protected o private. Las property strings son opcionales; además de las mencionadas, podemos encontrar frozen, que indica que no se puede cambiar el valor del atributo. En lo referente al nombre de los atributos, se deben tener en cuenta las siguientes pautas: • Se recomienda que comience por minúscula. • Cuando se trate de un atributo derivado (es decir, que es redundante con otros a partir de los cuales se puede obtener el valor), el nombre tiene que ir precedido de “/”. • Es conveniente que el nombre cumpla las reglas léxicas del lenguaje de programación, si no queremos que se tenga que cambiar al llegar al diseño. La expresión de tipo y el valor inicial también las deberán respetar. Se pueden utilizar indicadores de multiplicidad como en el caso de los vectores o matrices de acuerdo con el lenguaje. Uso de los indicadores de multiplicidad Consideremos: hijos [0..3]: persona o bien, hijos [3]: persona; en el primer caso podría haber entre 0 y 3 hijos, pero en el segundo tiene que haber exactamente tres. Ejemplo de clase con compartimento de nombre y compartimento de atributos Como se puede ver en la figura siguiente:
© Editorial UOC
47
Capítulo II. UML (I): el modelo estático
extremos serían las coordenadas de dos vértices opuestos del rectángulo, que lo determinan; Punto sería una clase descrita en el mismo paquete; gruesoLínea tiene el valor 1 por omisión, y área es un atributo derivado, ya que su valor se puede calcular a partir de las coordenadas de los puntos de extremos.
4.1.3. Especificación de las operaciones
Una operación se define de la siguiente forma: visibilidad nombre ‘(’ lista-de-parámetros ‘):’ tipo-de-retorno ‘{’property string‘}’ Se indica que una operación es operación de clase subrayando su definición. La visibilidad se señala igual que en el caso de los atributos. Conviene que el nombre de la operación y de los parámetros y el tipo de los parámetros y del retorno cumplan las reglas del lenguaje de programación. En la programación conviene que los nombres de las operaciones estén bien pensados, porque son la base del polimorfismo, en el que se aplica que “a igual concepto, igual nombre”.
Se recomienda que los nombres de las operaciones comiencen por minúscula. La lista de parámetros se compone de parámetros separados por comas; la sintaxis de cada uno es la siguiente: tipo nombre ‘:’ expresión-de-tipo ‘=’ valor-por-omisión Donde tipo es in, out o inout (por omisión, in), y nombre es el nombre del parámetro formal; expresión-de-tipo depende del lenguaje; valor-por-omisión depende del lenguaje y es opcional. El tipo-de-retorno sólo se tiene que utilizar cuando la operación devuelva un valor como resultado, y también se puede usar un parámetro out en su lugar. Opcionalmente, puede aparecer property strings: query, que denota que la operación no modifica el estado del sistema, y para especificar la semántica de concurrencia se pueden utilizar una de éstas: sequential, guarded o concurrent, y abstract, que indica que la operación es abstracta. Se pueden utilizar estereotipos poniéndolos encima de la operación afectada.
© Editorial UOC
48
Ingeniería del software
Ejemplo de clase con los tres compartimentos Tal y como se puede apreciar en el gráfico siguiente, la operación nuevoRectangulo es del estereotipo (no incluido dentro del UML) constructor y tiene dos parámetros in (por omisión); la operación calculoArea no tiene parámetros pero retorna un valor, cuyo tipo se indica.
4.2. La herencia en el análisis y el diseño
Sabemos que la herencia presupone que existan dos clases, de las cuales una desempeña el papel de superclase y la otra, el de subclase. Se dice que la relación entre una subclase y su superclase es una relación is_a_kind_of. La subclase comprende un subconjunto de los objetos de la superclase, los cuales, por tanto, tienen todos los atributos y operaciones de instancia de la superclase (se dice que la subclase los hereda) y, además, pueden tener algunos adicionales, específicos de la subclase. Según se defina primero la superclase o sus subclases, tenemos respectivamente dos tipos de herencia: herencia por especialización y herencia por generalización.
© Editorial UOC
49
Capítulo II. UML (I): el modelo estático
4.2.1. Herencia por especialización
Se llama de esta manera porque lo que se hace es crear una clase más especializada, más restrictiva, a partir de una clase definida con anterioridad. Ejemplo de especialización Consideramos que en la gestión de un hotel identificamos la clase Habitación y después nos damos cuenta de que hay una categoría especial de habitaciones que tiene atributos y/o operaciones diferentes, que son las suites; esto se representa de la siguiente forma:
La flecha con punta triangular vacía y cuerpo continuo expresa una relación entre subclase y superclase, y su sentido indica cuál es cada una. También se habla de que hemos creado una jerarquía de herencia, muy sencilla en algunos casos (como por ejemplo el caso de especificación) pero que llega a ser un árbol de diferentes niveles si hay superclases que presenten distintas subclases y subclases que sean a la vez superclases de otras. Incluso la jerarquía se convierte en una red si algunas clases tienen más de una superclase (herencia múltiple). El proceso mediante el cual reconocemos una subclase dentro de otra clase –que, consecuentemente, pasa a ser superclase de la primera– se denomina especialización o derivación.
© Editorial UOC
50
Ingeniería del software
4.2.2. Herencia por generalización. Clases abstractas
Supongamos que, al informatizar los impuestos de un municipio, encontramos, por un lado, los impuestos sobre las motos y por otro, los impuestos sobre los ciclomotores. Aunque inicialmente se había considerado que Motos y Ciclomotores son dos clases diferentes, después se ha observado que tienen algunos atributos y operaciones en común y, en consecuencia, se define una superclase común Veh2Ruedas
En este caso hemos procedido al revés: a partir de las subclases, hemos encontrado la superclase. Este proceso se denomina generalización. De la misma forma que en el ejemplo del hotel podía haber habitaciones que no fueran suites y, por tanto, había objetos que, de las dos clases, sólo pertenecían a Habitación, en este último, cualquier vehículo de dos ruedas es o bien una moto o bien un ciclomotor. Es decir, todos los elementos de Veh2Ruedas pertenecen a una u otra subclase y, por lo tanto, Veh2Ruedas es una clase artificial, un simple recurso para no describir dos veces lo que tienen en común Motos y Ciclomotores; se dice que Veh2Ruedas es una clase abstracta. Una clase abstracta es una superclase de la cual no se pueden crear (instanciar) directamente objetos, sino que se tienen que crear necesariamente en alguna de sus subclases.
© Editorial UOC
51
Capítulo II. UML (I): el modelo estático
Otro procedimiento En el proceso de generalización también se podría haber trazado una flecha independiente desde cada subclase a la superclase. La propiedad disjoint denota que todo objeto de la superclase pueda pertenecer sólo a una de las subclases como máximo.
Por esta razón se dice que las clases abstractas son no instanciables. Se indica que una clase es abstracta o bien poniendo su nombre en cursiva, o bien con la propiedad {abstract} en el compartimento del nombre. Una clase abstracta puede tener operaciones abstractas, que son las que sólo están implementadas en las subclases, en principio, de forma diferente en cada una. Una operación abstracta debe tener o bien su definición en cursiva, o bien la propiedad {abstract} al final de la misma.
4.3. Variantes en el concepto de clase
En este subapartado consideraremos diferentes tipos especiales de clases, pero no todos se pueden representar directamente en UML.
4.3.1. Clases diferidas
Las clases diferidas son clases abstractas que tienen alguna operación abstracta. También se denominan clases virtuales porque en algunos lenguajes como C++ o Delphi, los servicios de las características que acabamos de indicar se declaran virtual; en Java se declaran abstract, y en Eiffel, deferred. En UML se definen simplemente como clases abstractas.
4.3.2. Clases terminales
Muchas veces, y especialmente en frameworks, nos interesa bloquear los cambios que se podrían realizar con la herencia, porque al crear una subclase es fácil
© Editorial UOC
52
Ingeniería del software
que no se conozcan todas las dependencias y restricciones que se heredan, de modo que se pueden cometer errores.
Java permite calificar diferentes elementos como terminales: • Clases terminales, que son las que no pueden tener subclases. • Métodos terminales, que son aquellos que no pueden ser modificados en una subclase. • Atributos terminales, cuya visibilidad no se puede cambiar en una subclase. El UML no dispone de estos conceptos.
4.3.3. Metaclases
Las metaclases son clases cuyas instancias son clases. El concepto de metaclase raramente se encuentra implementado en los lenguajes orientados a objetos; un lenguaje que lo implementa es el CLOS (CLOS es la sigla de Common Lisp Object System), que fue creado por investigadores de inteligencia artificial y es un derivado del LISP. En UML, la metaclase es un estereotipo de la clase.
4.3.4. Clases parametrizadas o plantillas
Una clase parametrizada o plantilla (en inglés, template) es un descriptor de clase formalmente igual a una clase, excepto que algún término de su definición es un parámetro. ¿Qué es un parámetro de una plantilla? Un parámetro puede ser, por ejemplo, el nombre de una operación o atributo, el tipo de un atributo o de un parámetro o del resultado de una operación, el número de elementos de un atributo que sea una matriz o el número de bytes de un atributo de tipo string.
Cuando se dan valores a todos los parámetros de una plantilla se obtiene una clase totalmente especificada que, por tanto, no puede ser modificada directa-
© Editorial UOC
53
Capítulo II. UML (I): el modelo estático
mente, pero se pueden definir sus subclases. Aunque una plantilla no es propiamente una clase, se puede definir como subclase de una clase A, y entonces las clases que se han obtenido al dar valores a sus parámetros serán subclases de A. Ejemplo de clase parametrizada En el diagrama que vemos a continuación hemos definido una plantilla, hemos generado una clase y hemos dado un valor a cada parámetro. La relación entre la clase y la plantilla se puede representar de las dos formas indicadas:
Las clases parametrizadas se denominan clases genéricas* en algunos lenguajes de programación.
4.3.5. Clases de utilidad
A veces nos encontramos con rutinas que no corresponden a ninguna clase de operación, o bien con datos que no corresponden a ningún objeto determinado, por ejemplo, parámetros del sistema que sólo pueden tener un valor cada uno. Para incluir estas rutinas y datos dentro de un diagrama estático de UML, podemos definir una clase con el estereotipo utility, e incluir las rutinas como operaciones y los datos como atributos. *. Las clases genéricas en otros lenguajes. C++ y Eiffel soportan plenamente las clases genéricas pero con algunas diferencias, mientras que en Java se tienen que simular con la clase Object.
© Editorial UOC
54
Ingeniería del software
Puesto que esta clase no tendrá objetos, aunque los atributos y operaciones se definan formalmente como atributos y operaciones de instancia, será como si fuesen de clase y, por lo tanto, no se pueden definir ni operaciones ni atributos formalmente de clase. Ejemplo de clase de utilidad La clase de utilidad Arranque reúne diferentes elementos independientes relativos a la puesta en funcionamiento de un programa: dos parámetros y dos rutinas de inicialización.
4.4. Interfaces
Una interfaz describe un conjunto de operaciones visibles de una clase, sin indicar su implementación. Se dice que dicha clase en cuestión implementa la interfaz. Una interfaz no es una clase, pero equivale a una clase abstracta sin atributos y con todas sus operaciones diferidas. Las interfaces pueden establecer relaciones de herencia entre sí, pero no pueden participar en asociaciones ni tener estados. Cada interfaz acostumbra a especificar sólo una parte del comportamiento de una clase. Una clase puede implementar diferentes interfaces, si al menos una de éstas no posee todas las operaciones visibles de la clase. En cambio, una interfaz sólo es implementada por una clase. La notación de la interfaz es como la de la clase pero con el estereotipo interfaz y sin el compartimento de atributos, porque no los tiene.
© Editorial UOC
55
Capítulo II. UML (I): el modelo estático
Ejemplo de una interfaz con clase que la utiliza y otra que la implementa El siguiente ejemplo se ha inspirado en la librería de Eiffel:
La interfaz Comparable pretende declarar todas las operaciones que deberán tener las clases que quieran permitir que dos de sus objetos se puedan comparar según algún criterio de igualdad que sólo se define dentro de la implementación de la operación esIgual dentro de la clase Cadena, que es la que implementa Comparable. La clase ClaseCliente utiliza la interfaz Comparable, en el sentido de que la implementación de alguna operación de ClaseCliente llama alguna operación de Comparable. ¡Prestad atención a cómo es cada flecha! Una notación equivalente más abreviada del mismo ejemplo es ésta:
© Editorial UOC
56
Ingeniería del software
5. Representación de los objetos
Un objeto se representa gráficamente de una manera muy parecida a las clases; se indican los valores en los atributos de instancia y, opcionalmente, un nombre en el objeto, que va seguido de “:” y del nombre de la clase, todo subrayado. Se puede omitir el tipo de los atributos, así como el compartimento de las operaciones, porque los dos elementos ya se conocen gracias a la especificación de la clase.
También se puede representar la relación, denominada instanciación, entre un objeto y la clase a la cual pertenece.
© Editorial UOC
57
Capítulo II. UML (I): el modelo estático
6. Relaciones entre clases
Sintácticamente, los lenguajes de programación permiten sólo dos tipos de relaciones entre clases: de herencia, que ya hemos visto, y cliente-servidor. Por relación cliente-servidor se entiende que un objeto (el cliente) pida a otro (el servidor), mediante un mensaje, que ejecute una operación de las definidas en la clase del servidor. En lo que respecta al análisis y el diseño, se consideran otros tipos de relaciones, porque las relaciones cliente-servidor son demasiado simples para describir el mundo real. Desacuerdo entre autores y el estándar de tipo relación Lamentablemente, no existe acuerdo entre los autores más importantes sobre cuáles son estos tipos (y menos todavía sobre su semántica y notación). Sin embargo, si el UML, convertido en estándar, se acaba imponiendo, es probable que su versión sea aceptada por todos o casi todos. No obstante, si el UML permite modelar gráficamente diferentes tipos de relaciones entre clases (agregación, asociación y uso), el significado de cada uno no queda concretado en los documentos oficiales del OMG y, por lo tanto, la decisión sobre cuándo se debe aplicar un tipo de relación u otro será a menudo una interpretación personal.
6.1. Asociaciones Dentro de este subapartado veremos los conceptos y terminología utilizados para designar las asociaciones y los diferentes tipos existentes.
6.1.1. Concepto y terminología Hay una asociación entre clases cuando una clase necesita otra u otras para la implementación de sus operaciones, lo cual se cumple por medio del paso de mensajes entre éstas. Una asociación se define partiendo de la clase, y se concreta en la existencia de enlaces (en inglés, links) entre objetos concretos de las clases relacionadas por la asociación.
© Editorial UOC
58
Ingeniería del software
Dentro de una asociación, se considera que cada clase desempeña un papel (en inglés, role) determinado; cada papel tiene asociada una cardinalidad. Entre las mismas clases puede haber asociaciones diferentes con significado distinto. Una asociación puede tener nombre, que sirve para identificar su significado, y también se puede dar un nombre a cada uno de los papeles de las clases.
6.1.2. Asociaciones binarias y n-arias
Asociaciones binarias son las que tienen lugar entre dos clases. Las dos clases pueden ser la misma (asociación reflexiva), y en este caso es posible permitir que un objeto esté enlazado consigo mismo o que no lo esté. En una asociación binaria, la cardinalidad de un papel A es el número de objetos del otro papel B al que puede estar enlazado cada objeto de A; se indica el valor máximo y mínimo de este número. Ejemplos de asociaciones binaria y reflexiva 1) Asociación binaria Como se puede apreciar en la siguiente asociación binaria:
La asociación significa que una persona trabaja en una empresa (no al revés, observad el sentido indicado por la punta de flecha coloreada); la empresa es la que ofrece el empleo y la persona desempeña el papel de empleado. Cada persona concreta puede tener una empresa que ofrece el empleo o ninguna, mientras que una empresa puede tener un empleado como mínimo y cualquier número como máximo, según indican las cardinalidades. La punta de flecha abierta encima de la línea de la asociación indica que se puede acceder (navegar) de una empresa hacia sus empleados.
© Editorial UOC
59
Capítulo II. UML (I): el modelo estático
2) Asociación reflexiva Consideremos la figura siguiente:
El significado de esta asociación es que un trabajador depende de un jefe; tanto el jefe como el subordinado son trabajadores. Cada trabajador puede tener como máximo un jefe, mientras que un jefe puede tener cualquier número de subordinados (el asterisco solo indica que el número puede ser cualquiera, incluso el cero). Un trabajador no puede ser jefe de sí mismo, pero eso no lo indica la notación gráfica.
Una relación ternaria es aquella que tiene tres papeles, y en general una relación n-aria es la que tiene n papeles. Las relaciones no binarias, ya que no se pueden representar mediante una línea, se representan por medio de un rombo. Ejemplo de asociación ternaria Observemos la siguiente asociación:
Un chófer determinado puede conducir un autocar determinado en cualquier número de excursiones (“0..*” es equivalente a “*”), pero en una excursión concreta, un chófer sólo puede conducir un autocar, y en una excursión en particular, un autocar sólo puede tener un chófer.
© Editorial UOC
60
Ingeniería del software
El establecimiento de enlaces según una asociación El establecimiento de enlaces entre objetos según una asociación puede ser una operación de alguna de las clases asociadas, igual que la navegación de un objeto a otro enlazado a éste.
El significado de la cardinalidad en una asociación ternaria es el siguiente: la cardinalidad del papel A expresa los límites al número de objetos de A que pueden estar enlazados en cada combinación concreta de un objeto del papel B y otro del papel C.
6.1.3. Clases asociativas
En principio, una asociación no es una clase: no tiene por qué tener atributos ni operaciones, y puede carecer incluso de nombre. No obstante, si una asociación debe tener atributos y operaciones propias o bien uno de los dos, entonces es preciso que se defina como clase. En este caso se habla de clase asociativa. Una clase asociativa se representa como una clase colgada del símbolo de la asociación (la línea, en el caso de una asociación binaria, o el rombo en los otros casos) por medio de una línea discontinua. Ejemplo de clase asociativa binaria El caso que presentamos aquí es el mismo que el del ejemplo de asociación binaria, excepto por el hecho de que aquí la asociación tiene un atributo. Puesto que la asociación ahora es una clase, se le ha añadido una operación para crear instancias, y también se le ha cambiado el nombre por uno más apropiado para una clase.
© Editorial UOC
61
Capítulo II. UML (I): el modelo estático
6.1.4. Asociaciones calificadas
Veremos mejor este concepto si lo introducimos mediante un ejemplo. Consideremos una clase Departamento y otra Empleados, que tienen un atributo categoría, y queremos establecer una asociación separada entre el departamento y sus empleados para la categoría A, la categoría B, etc. Una forma de hacerlo es con una relación ternaria, así:
Esta solución es un poco forzada, porque obliga a convertir un atributo en una clase independiente, circunstancia que se puede evitar mediante una asociación calificada en la cual el atributo calificador sea la categoría del empleado. Esto se representa de la siguiente forma:
Este diagrama se puede interpretar de esta manera: cada empleado tiene un departamento, y dentro de un departamento tiene que haber al menos un empleado de cada categoría (mientras que si tuviéramos una asociación binaria or-
© Editorial UOC
62
Ingeniería del software
dinaria, prescindiendo de la categoría, cualquier departamento tendría al menos un empleado, de una categoría u otra).
6.1.5. Asociaciones alternativas
Puede ocurrir que en una clase que participe en dos asociaciones, cada objeto concreto participe en una o en la otra, pero no en las dos. Entonces se habla de asociaciones alternativas. Ejemplo de asociaciones binarias alternativas Una forma de representar las asociaciones binarias alternativas se puede apreciar en la figura:
Un servicio determinado puede ser prestado por un proveedor autónomo o bien por una empresa, pero nunca por uno y otra a la vez. Esto también se podría describir así:
© Editorial UOC
63
Capítulo II. UML (I): el modelo estático
6.1.6. Asociaciones derivadas Una asociación derivada es una asociación redundante que se puede obtener como combinación de otras relaciones del modelo. Ejemplo de asociación derivada En la figura representamos la siguiente asociación derivada:
donde alumnos del curso es una asociación derivada, porque los alumnos de un curso se pueden determinar recorriendo las asignaturas del curso y encontrando a los alumnos de cada una. Sin embargo, también podría ocurrir que esta relación se definiese de una manera no redundante, por ejemplo, que comprendiese a los alumnos que estuviesen matriculados sólo en asignaturas de dicho curso. Entonces no se pondría “/”, que es el indicador de elemento derivado, como hemos visto al hablar de los atributos derivados en el subapartado 5.1.2.
6.2. Agregaciones y composiciones
En este subapartado consideramos las agregaciones y las composiciones.
6.2.1. Agregaciones
Una agregación es un caso particular de asociación binaria en la cual uno de los papeles tiene el significado de ‘parte’ y el otro el de ‘todo’, en algún sentido.
© Editorial UOC
64
Ingeniería del software
Denominaremos componentes a la clase correspondiente al primer papel y a sus objetos, y clase y objetos agregados, a los del segundo papel. Se dice que una agregación es una relación is-part-of. Las agregaciones pueden tener diferentes significados: • Acoplamiento-piezas. Una máquina y sus piezas, un circuito eléctrico y sus componentes, un sistema de software y sus programas; cada parte tiene un papel concreto y no se puede cambiar por ninguna otra. • Continente-contenido. Un avión y los pasajeros que transporta, que no constituyen el avión, ya que un avión sin pasajeros es por sí solo un avión. • Colectivo-miembros. Un grupo excursionista y sus excursionistas, o bien una promoción de alumnos y dichos alumnos; se supone que los miembros no tienen papeles diferenciados y, por tanto, son intercambiables. Un objeto compuesto puede tener objetos componentes que pertenecen a diferentes clases o, dicho de otra forma, una clase puede tener relaciones de agregación con otras diferentes. Una clase puede desempeñar el papel de clase compuesta en una agregación y el de clase componente en otra, y también es capaz de realizar los dos papeles en la misma agregación (aunque un objeto no puede ser componente de sí mismo). Entre dos clases puede haber más de una agregación. Ejemplo de agregaciones A continuación se representa la composición clásica de un equipo de fútbol:
Cada jugador juega en un equipo (el del club al que pertenece) o en ninguno, y un jugador sólo puede estar en una de las cuatro posiciones, como indica {or}. Se supone
© Editorial UOC
65
Capítulo II. UML (I): el modelo estático
que las de defensa, por ejemplo, son intercambiables entre sí, o de otro modo habría once agregaciones diferentes. El rombo vacío en la parte de la clase compuesta u objeto compuesto denota que se trata de una agregación.
6.2.2. Composiciones y objetos compuestos
La composición (o agregación de composición) es un caso particular de la agregación. En una composición, los objetos componentes no tienen vida propia sino que, cuando se destruye el objeto compuesto del que forman parte, también se destruyen. Además, un objeto componente sólo puede formar parte de un objeto compuesto y no puede pasar de un objeto compuesto a otro. Estas restricciones no existen en el caso de agregaciones en general. En el ejemplo de agregaciones que hemos visto antes, los jugadores pueden pasar de un equipo a otro y existen por sí mismos incluso cuando no están en ningún equipo. Por tanto, las agregaciones en cuestión no son composiciones. En una composición denominaremos a la clase agregada clase compuesta, y al objeto agregado, objeto compuesto. Ejemplos de composición y de objeto compuesto 1) Ejemplo de composición Consideremos la composición siguiente:
Un centro universitario (facultad, etc.) pertenece a una sola universidad (de hecho, por la parte de la clase compuesta, la cardinalidad en una composición es siempre 1).
© Editorial UOC
66
Ingeniería del software
Una universidad debe tener, al menos, un centro universitario. Suponemos que si desaparece una universidad desaparecen también sus centros universitarios, y que éstos no se trasladan de una universidad a otra. 2) Ejemplo de objeto compuesto Puesto que en una composición cada objeto componente sólo puede pertenecer a un único objeto compuesto, podemos representar los objetos componentes dentro del objeto compuesto en un compartimento especial.
6.3. Relaciones de dependencia
Una relación de dependencia expresa que un elemento del modelo –denominado cliente– depende para su implementación o funcionamiento de otro elemento –denominado suministrador (en inglés, supplier). El símbolo de una relación de dependencia es una flecha de línea discontinua y punta abierta. Existen diferentes estereotipos estándar, alguno de los cuales ya hemos visto, y se pueden definir otros más: • derive: significa que un elemento se obtiene de otro por medio de un cálculo o algoritmo; • friend: da acceso al cliente a los elementos de visibilidad private contenidos en el suministrador; • refine: quiere decir que el cliente procede históricamente del suministrador, del cual es una versión nueva o enriquecida (por ejemplo, una clase descrita en el análisis en el que se realizan cambios en el diseño);
© Editorial UOC
67
Capítulo II. UML (I): el modelo estático
• trace: relaciona elementos que corresponden desde un punto de vista semántico al mismo concepto, como por ejemplo un elemento y su implementación; • call, create y send; • extend e include: que existen sólo entre casos de uso.
7. Comentarios y restricciones
7.1. Comentarios
Un comentario se pone dentro de un rectángulo con un vértice doblado, enlazado con un línea discontinua al elemento al cual se refiere.
7.2. Restricciones
Las restricciones (en inglés, constraints), expresan condiciones que debe cumplir el elemento del modelo al cual se asocian. Se representan del mismo modo que los comentarios, salvo que van entre llaves {}, lo cual indica que pueden ser interpretadas por las herramientas CASE. Las especificaciones del UML incluyen un lenguaje para la descripción de las restricciones, denominado OCL. No obstante, se puede utilizar el UML sin usar este lenguaje. OCL es la sigla de Object Constraint Language.
© Editorial UOC
68
Ingeniería del software
7.2.1. Las restricciones de las operaciones: la programación por contrato
En el UML hay tres tipos de restricciones relativas a las operaciones: precondiciones, postcondiciones e invariantes. • Las precondiciones son restricciones que se deben cumplir antes de ejecutar una operación. Su cumplimiento nos garantiza que la operación se ejecuta partiendo de un estado correcto del sistema. • Las postcondiciones se comprueban al acabar la ejecución de una operación, y garantizan que cuando esté terminada la operación, el sistema vuelva a situarse en un estado correcto. • Las invariantes son condiciones que se deben cumplir en todo momento. Se tienen que comprobar al inicio de cualquier operación –excepto los constructores– y al acabar. Las restricciones pueden servir para diseñar con vistas a hacer programación por contrato, que se basa en unas condiciones sobre operaciones y objetos denominadas aserciones, las cuales se pueden expresar en forma de restricciones del UML.
© Editorial UOC
69
Capítulo II. UML (I): el modelo estático
Conclusiones
En este capítulo hemos estudiado el modelo estático del UML. Se han descrito los diferentes elementos del modelo, y de cada uno se ha descrito la notación. Estos conceptos son los siguientes: • Las clases, con sus variantes (clases abstractas, metaclases y otras) y conceptos relacionados con la clase (clasificador, interfaz, plantilla) y la herencia. • Las relaciones entre clases (asociaciones, agregaciones, relaciones de dependencia). • Los comentarios y las restricciones.
© Editorial UOC
71
Capítulo III. UML (II): el modelo...
Capítulo III
UML (II): el modelo dinámico y de implementación
Hemos visto que el modelo estático del UML consiste esencialmente en un único diagrama, el de clases, que se tiene que elaborar en todo proyecto de software. El modelo dinámico y de implementación, en cambio, comprende diferentes diagramas, en parte relacionados entre sí y también con el diagrama estático. Algunos de estos diagramas sólo se utilizan en determinados casos. Los aspectos dinámicos o de comportamiento del sistema se pueden modelar con los siguientes diagramas: el diagrama de casos de uso, el diagrama de estados y transiciones, el diagrama de actividad y los diagramas de interacción, que son el de secuencias y el de colaboración. La implementación se puede modelar con el diagrama de componentes y el de despliegue.
1. El diagrama de estados
A veces hay objetos cuyo comportamiento puede variar a lo largo del tiempo; cuando esto sucede, se dice que el objeto tiene estados. Existen algunos tipos de aplicaciones, como las de tiempo real, para las cuales el modelado de estados es especialmente importante. Información redundante, pero aclaratoria... La información que contiene el diagrama de estados es esencialmente redundante, ya que los cambios de estado son resultado de la dinámica del sistema y, por tanto, de la ejecución de las operaciones de la misma clase o de otras. No obstante, aun así, re-
© Editorial UOC
72
Ingeniería del software
presenta otro punto de vista sobre la dinámica de una parte del sistema que puede contribuir decisivamente a comprenderla mejor.
En el diagrama de estados o diagrama dinámico tenemos que distinguir los siguientes elementos: • Las diferentes situaciones en que se puede encontrar un objeto (los estados). • Qué cambios de estado son posibles (transiciones). • Cuál es el hecho que los produce (acontecimientos). En las especificaciones del UML se habla de máquinas de estados para distinguirías de los diagramas de estado clásicos o de Harel, con los cuales existen diferencias. Sin embargo, nosotros utilizaremos el término diagrama de estados porque siempre representamos las máquinas de estado en forma de diagrama. No puede haber ninguna confusión, ya que en esta asignatura no se tratarán los diagramas de Harel. Ejemplos de estados Hay objetos a los cuales no se puede pedir alguna de sus operaciones en cualquier momento, u objetos para los que alguno de sus atributos sólo puede tener un valor no nulo en circunstancias determinadas.
El diagrama de estados se utiliza normalmente para describir objetos del dominio del usuario y se documenta por lo general en la etapa de análisis.
1.1. Conceptos básicos
A continuación explicaremos una serie de conceptos básicos: 1) Un estado es una situación determinada dentro de la vida de un objeto o la duración de una interacción durante la cual cumple alguna condición, lleva a cabo alguna acción o espera que se produzca un acontecimiento. Un estado no corresponde a un instante en el tiempo, sino que el objeto o interacción permanece en éste un tiempo finito.
© Editorial UOC
73
Capítulo III. UML (II): el modelo...
2) Una transición simple consiste en que el objeto o interacción pasa de un estado (estado de origen) a otro (estado de destino), que podría volver a ser el mismo. En el caso más general, este paso comienza cuando se produce un acontecimiento determinado y al mismo tiempo se cumple una condición especificada (condición de guarda). Entonces se pueden ejecutar unas acciones y se pueden enviar mensajes a objetos individuales o a conjuntos de objetos. Un estado puede tener transiciones de llegada, una de las cuales será el estado de destino, y transiciones de salida, una de las cuales será el estado de origen. 3) Las transiciones internas* son seudotransacciones en las cuales no hay cambio de estado. Sirven para especificar acciones que se deben ejecutar en respuesta a un acontecimiento que no provoca ningún cambio de estado en el objeto o interacción en cuestión. 4) Una acción es la especificación de un proceso atómico, es decir, que o no se ejecuta o se ejecuta hasta el final. Como consecuencia de una transición, se puede ejecutar una acción o más. Es posible describir una acción mediante un procedimiento o una máquina de estados. 5) Los objetos, por medio de mensajes, pueden recibir peticiones de operaciones o señales. Las señales, a diferencia de las operaciones, no realizan ningún proceso, y el único efecto directo que pueden tener es producir acontecimientos (que sí pueden provocar transiciones y la consiguiente ejecución de acciones). 6) Los acontecimientos (en inglés, events) son hechos que, cuando se producen, pueden provocar transiciones de un estado a otro en objetos e interacciones y/o la ejecución de determinadas acciones. Un acontecimiento no está vinculado a ningún objeto o clase en particular, sino que es un hecho que puede afectar en general a los elementos del paquete en cuyo interior está definido. Cada acontecimiento posee un nombre que lo identifica dentro del paquete, y puede tener parámetros. Normalmente, un acontecimiento se tiene que tratar en el momento en que se produce. En caso contrario, se provoca la transición porque el objeto o interacción no está en el estado correspondiente: se pierde el acontecimiento a no ser que se declare como acontecimiento diferido. *. Conviene no confundir una transición interna con una a-totransición, que es una transición ordinaria en la cual el estado de origen y el estado de destino son el mismo.
© Editorial UOC
74
Ingeniería del software
Tipos de acontecimientos Ahora veremos diferentes tipos de acontecimiento: • De llamada. Se producen cuando se llama una operación del objeto al que corresponde el diagrama. • De señal. Representan la recepción de una señal por el objeto a la que corresponde el diagrama. • De cambio. Representan una notificación de que una condición ha llegado a ser cierta. Esta condición no se tiene que confundir con condición de guarda, ya que una guarda se evalúa una vez se ha presentado el acontecimiento correspondiente a una transición para determinar si se provoca la transición o no, mientras que esta condición produce el acontecimiento cuando ha llegado a ser cierta. • De tiempo. Representan la notificación de que o ha pasado un periodo de tiempo desde que se ha producido un acontecimiento determinado (por ejemplo, que se ha entrado en el estado de origen de la transición), o de que es una hora determinada. Acontecimientos internos Son seudoacontecimientos, ya que están vinculados a un estado en lugar de a una transición, y sirven para poner en marcha acciones que no van asociadas a ningún cambio de estado concreto. Existen tres tipos de acontecimientos internos: 1) De entrada. Se producen cuando el objeto entra en el estado correspondiente. No tienen ni guarda ni parámetros, porque se nombrarán implícitamente cuando haya una transición de entrada en el estado (incluida una autotransición), pero no cuando haya una transición interna, ya que entonces no se producirá un cambio de estado. Se especifican explícitamente y tienen como nombre la palabra clave entry. 2) De salida. Son análogos a los de entrada, salvo que se producen a la salida del estado. Se especifican explícitamente y tienen como nombre la palabra clave exit. 3) De acción. Especifican acciones que se ejecutan cuando se llega al estado en cuestión y acaban por sí mismas o cuando se sale del estado. Se especifican explícitamente y tienen como nombre la palabra clave do.
1.2. Notaciones básicas
La representación más sencilla de un estado es un rectángulo con los vértices redondeados, tal y como podemos observar en la siguiente figura:
© Editorial UOC
75
Capítulo III. UML (II): el modelo...
En la práctica, es imprescindible que cada estado tenga un nombre y que este nombre no se repita en ningún otro estado del mismo diagrama. Este hecho no impide que el objeto o interacción pueda llegar al mismo estado varias veces a lo largo de su vida. Las transiciones se representan mediante flechas de punta coloreada que van del estado de salida al de llegada. Con la flecha se encuentra una expresión (denominada cadena de la transición) que presenta la siguiente sintaxis formal: signatura ‘[’ guarda ‘]’ ‘/’ acción ‘^’ envío Puede haber varias acciones o envíos o no haber ninguno, y pueden estar mezclados. El orden en que aparecen es en el que se deben ejecutar. A continuación veremos una explicación de cada uno de los elementos de la cadena de transición: • Signatura. Tiene un formato que depende del tipo de acontecimiento. En el caso de un acontecimiento de llamada o de señal, se define así: nombre_acontecimiento ‘(’ nombre_parámetro ‘:’ expresión_tipo ‘,’ ... ‘)’ Si el acontecimiento es de tiempo, la signatura adopta una de estas formas: ‘after(’ expresión_de_tiempo ‘)’ donde expresión_de_tiempo consiste en una duración a partir de un origen, o: ‘when(’ hora o fecha ‘)’ Finalmente, si el acontecimiento es de cambio, tendremos lo siguiente: ‘when(’ expresión_booleana ‘)’ Nota terminológica Respecto al uso de términos parámetro y argumento en relación con una llamada, hay que tener presente que parámetro corresponde al punto de vista de lo que se llama, y argumento, al punto de vista de lo que hace la llamada.
© Editorial UOC
76
Ingeniería del software
• Guarda. Es una expresión que puede tomar el valor verdadero o falso, escrita en seudocódigo o en el lenguaje de programación que se utiliza. • Acción. Es la especificación de una acción, en seudocódigo o en el lenguaje de programación que se usa. En el caso de un acontecimiento diferido, debe aparecer la palabra clave defer como primera acción. • Envío. Este elemento presenta la forma siguiente: destino ‘.’ mensaje ‘(’ argumento ‘,’ ... ‘)’ en el que destino tiene que identificar un objeto o grupo de objetos y mensaje puede ser una operación del objeto de destino o una señal. Las señales se pueden definir como clases con el estereotipo signal. No tienen operaciones, y en el compartimento de los atributos tienen los parámetros de la señal. Pueden constituir jerarquías de herencia, pero no les es posible establecer relaciones de ningún tipo con clases. Las señales a las cuales deben ser sensibles los objetos de una clase se pueden especificar en un compartimento adicional del símbolo de la clase. Ejemplos de diagramas de estado En los ejemplos siguientes veremos diagramas de estados con transiciones, estados, acontecimientos, autotransición, etc. 1) Ejemplo de estados, transiciones y acontecimientos Este diagrama corresponde a una clase de facturas, cuyo nombre no aparece:
© Editorial UOC
77
Capítulo III. UML (II): el modelo...
Todo comienza cuando llega una factura, hecho que describimos como el acontecimiento llegada, que tiene como parámetro la fecha. Este acontecimiento pide la operación constructor de dicha clase en relación con un objeto de la clase que es la factura llegada (identificada por factura) y provoca la transición hacia el estado Recibida; fecha, y proveedor son parámetros de constructor. Después, la factura es verificada (esto no aparece explícitamente), lo cual puede dar como resultado dos acontecimientos alternativos: aceptación –que pide la operación aceptar y provoca la transición hacia el estado Aceptada–, y error –que pide, a su vez, la operación retorno y provoca la transición al estado Devuelta. Si la factura está en el estado Aceptada y se produce el acontecimiento pago, la factura pasa al estado Final y se pide la ejecución de la operación pagar en relación con dicha factura. Si la factura está en el estado Devuelta, la transición hacia el estado Final es provocada por un acontecimiento de tiempo que consiste en que hayan pasado tres días (puesto que no se especifica desde cuándo, se entiende que es desde la entrada en el estado de origen), y entonces se pide la operación borrar. 2) Ejemplo de autotransición, acción y guarda El diagrama siguiente representa parte del diagrama de estados de los objetos de una clase de libros de una biblioteca pública:
Cuando un lector tiene un libro en préstamo, puede pedir renovaciones, que se le concederán si otro lector no lo ha reservado. Los efectos del acontecimiento peticion_renovacion son la autotransición, la llamada a la operación renovacion y la ejecución de la acción estadisticas. 3) Ejemplo de acontecimiento de señal Un lector tiene un libro en préstamo. Cuando lo devuelve, si otro lector lo ha reservado, se envía un mensaje al objeto reserva con la señal devuelta, que debe estar definida dentro del compartimento de señales de la clase a la cual pertenece reserva.
© Editorial UOC
78
Ingeniería del software
1.3. Transiciones complejas
Un objeto o interacción puede estar en más de un estado al mismo tiempo, y puede haber transiciones que salgan de más de uno o que vayan a parar a más de uno, o ambas cosas a la vez. Son las denominadas transiciones complejas. Una transición compleja con varios estados de origen sólo tiene lugar si el objeto o interacción está en todos estos al mismo tiempo y, además, se produce el acontecimiento correspondiente a la transición (y se cumple la guarda, si la hay) y, por tanto, realiza una función de sincronización. Por analogía, cuando se produce una transición compleja con varios estados de destino, el objeto o interacción pasa a todos estos estados a la vez. Una transición compleja se representa utilizando un seudoestado* intermedio, al que van a parar varias transiciones (seudoestado de sincronización, join pseudo-state) o del que salen varias (seudoestado de bifurcación, fork pseudostate), o ambas circunstancias al mismo tiempo. Este tipo de seudoestado se representa por medio de una barra vertical corta y gruesa que es origen y destino de transiciones en las cuales se descompone la transición compuesta. Ejemplo de transiciones complejas Considerad las siguientes transiciones complejas:
*. Seudoestado. Un seudoestado es un símbolo que figura en una posición del diagrama donde normalmente habría un estado, y no representa ningún concepto, sino que tiene una función puramente gráfica.
© Editorial UOC
79
Capítulo III. UML (II): el modelo...
Cuando llega una factura de una compra de material, pasa a estar pendiente de la verificación mediante la comparación con el pedido (V1) y con lo que se ha recibido (V2), por medio de una transición compleja de bifurcación. Si de cada verificación resulta una conformidad (acontecimientos OK1 y OK2), se pasa al estado Revisado1 y Revisado2, respectivamente. Cuando llega el día 30, se paga la factura sólo si estaba al mismo tiempo en estos dos estados, por medio de una transición compleja de sincronización.
1.4. Estados compuestos
Hemos visto que mientras un objeto o interacción permanece en un estado, se encuentra en una situación determinada. Sin embargo, a veces esta situación es genérica, y mientras permanece en ella –y sólo en este caso–, puede estar en diferentes momentos en lo que podríamos considerar variantes o matices de la situación genérica. Una situación genérica como ésta se representa mediante un estado compuesto, en el que hay varios subestados posibles, cada uno de los cuales puede ser un estado compuesto a su vez o no. Los estados no compuestos –todos los que hemos considerado hasta el momento– se denominan estados simples. A un estado compuesto le corresponde un diagrama de subestados. Los subestados de un estado pueden ser concurrentes (es decir, que se pueden presentar de forma simultánea), o secuenciales (incompatibles entre sí). En el caso más general, el diagrama de subestados consta de varias secuencias de subestados en paralelo. Cada secuencia comienza en un seudoestado inicial y acaba en un seudoestado final. Un estado compuesto está representado por el mismo símbolo que un estado simple, pero en su interior habrá al menos dos compartimentos separados por una línea: arriba el del nombre y abajo el que contiene su diagrama de subestados. Cada secuencia de subestados ocupará una franja horizontal separada de las franjas adyacentes por una línea discontinua. Un subestado inicial se representa con un círculo lleno, y uno final con un círculo lleno envuelto en una circunferencia. Las transiciones entre subestados de la misma secuencia se representan igual que entre estados. Las transiciones entre estados que pertenecen a secuencias diferentes usan seudoestados de sincronización de la manera que veremos en el ejemplo correspondiente.
© Editorial UOC
80
Ingeniería del software
Existen varios tipos de transiciones que tienen por estado de origen o de destino un objeto compuesto: • Transiciones que entran directamente en un subestado o salen del mismo. • Transiciones que entran o salen del estado compuesto, considerado como una unidad. Si entra, es como si la transición tuviera como estados de destino los estados iniciales de todas las secuencias, mientras que si sale, es como si la transición tuviera como estados de origen los estados finales de todas las secuencias. • Transiciones que tienen como destino un indicador de historia de los estados, el cual es un seudoestado que indica que en una transición de regreso al estado compuesto se vuelve, dentro de éste, al mismo subestado (dentro de la secuencia contenida en la misma franja que dicho indicador de historia) del que salió la última vez que partió del estado compuesto. Si el subestado puede ser un estado compuesto, hay una opción que indica que se vuelva también a un subestado de éste, seleccionado de la misma forma, y esto para tantos niveles de subestados como haya. Del indicador de historia puede salir una transición hacia un subestado que será el de destino, en el caso de que la transición tenga lugar sin que anteriormente hubiera estado ninguna vez en el estado compuesto. Véase el segundo ejemplo a continuación. • Transiciones stubbed. Estas transiciones tienen como estado de destino (origen) algún subestado de un estado compuesto del que no se especifica el diagrama de subestados. Dicho subestado no puede ser inicial (final), ya que, en el caso contrario, podríamos tener como estado de destino (origen) el estado compuesto, según se ha explicado anteriormente. Ejemplos de transiciones que tienen por estado de origen o destino un estado compuesto Ahora veremos tres ejemplos de estas transiciones: 1) Ejemplo de estado compuesto Este ejemplo describe el mismo caso que el ejemplo de transiciones complejas, pero esta vez, por medio de un estado compuesto (de nombre EnVerificacion). Este estado no tiene compartimento de transiciones internas.
© Editorial UOC
81
Capítulo III. UML (II): el modelo...
2) Ejemplo de transiciones con subestados, indicador de historia y seudoestado de sincronización Observemos la figura siguiente:
Desde el estado Est1 se va al estado compuesto Est2 en general (es decir, a todos sus estados iniciales a la vez) si se produce el acontecimiento ev1 y se cumple la guarda g1. En cambio, si con el mismo acontecimiento se cumple la guarda g2, entonces se pasa al subestado de Est2, donde se estaba antes de salir de Est2 (observad que se puede haber salido tanto desde Sub1 como desde Sub3) si es que se había estado alguna vez en el mismo, y si no se pasa a Sub1. Si Sub1 o Sub3 tuvieran subestados, se iría al subestado de éstos en el que se estaba cuando se salió de Est2 por última vez (esto lo indica el hecho de que la H del indicador de historia vaya acompañada de un asterisco). Se puede pasar de Sub1 a Sub4 –que pertenece a otra secuencia– por medio de un seudoestado de sincronización y una transición compleja de sincronización. El asterisco dentro del símbolo del estado de sincronización denota que no hay límite máximo en el número de veces que se puede disparar la transición hacia Sub4 como
© Editorial UOC
82
Ingeniería del software
consecuencia de que se produce repetidamente ev6 mientras se está ininterrumpidamente en Sub1 (si hubiera un valor máximo, se pondría en lugar del asterisco). Del estado Est4 se pasa directamente al subestado Sub2. 3) Ejemplo de transiciones stubbed Este ejemplo describe el mismo caso que el ejemplo anterior, pero ahora las transiciones que entran y salen de subestados no especifican de cuáles. Sin embargo, las transiciones que entran y salen del estado compuesto en su conjunto se indican de la misma forma que antes.
1.5. Notación ampliada del estado
Igual que la clase, el estado tiene dos representaciones gráficas: una que sólo tiene el nombre, que es la que hemos utilizado hasta el momento, y otra con varios compartimentos. Los compartimentos son los siguientes: • Compartimento del nombre, que contiene sólo el nombre del estado. • Compartimento de las transiciones internas y los acontecimientos internos. Contiene una lista de las cadenas de los acontecimientos y seudoacontecimientos correspondientes. En el caso de los seudoacontecimientos entry y exit, no puede haber ni condiciones de guarda ni parámetros. • Compartimento del diagrama de subestados, que ya hemos visto, en el caso de estados compuestos.
© Editorial UOC
83
Capítulo III. UML (II): el modelo...
2. El diagrama de casos de uso Los diagramas de casos de uso (en inglés, use case) sirven para mostrar las funciones de un sistema de software desde el punto de vista de sus interacciones con el exterior y sin entrar ni en la descripción detallada ni en la implementación de estas funciones. Los casos de uso se utilizarán tanto en la recogida y documentación de requisitos como en el análisis.
2.1. Actores
La finalidad de un software es proporcionar información a personas, máquinas y dispositivos o software del exterior, cuyo conjunto denominaremos entidades exteriores. También hay entidades exteriores –las mismas u otras– que piden funciones al software o le suministran información para que la trate. Un actor es un conjunto de papeles de una entidad exterior en relación con el sistema de software considerado. Por tanto, un actor no es la entidad exterior en sí, sino sólo los aspectos que tienen que ver con su interrelación con el sistema de software; podríamos decir que un actor es la visión que el software tiene de una entidad exterior. Desde este punto de vista, un actor es un conjunto de papeles, ya que se considera que el actor desempeña un papel diferente en cada interacción (cada caso de uso, en el UML) que tiene con el software. Además, si una entidad exterior forma dos conjuntos de papeles con poca relación entre sí, le corresponderán dos actores diferentes (se podría decir que, en este caso, el software no puede saber si los dos actores son o no la misma entidad exterior). A menudo hay discusiones sobre si una entidad exterior en particular es o no un actor en relación con un software. Nosotros consideraremos que para ser actor, una entidad exterior tiene que cumplir estas dos condiciones: 1) Ser autónoma con respecto al software, es decir, que la actividad en que utiliza la información suministrada por el software no esté subordinada a la de éste.
© Editorial UOC
84
Ingeniería del software
2) Mantener relación directa con el software o con entidades exteriores que desempeñan tareas subordinadas a la actividad del software. Ejemplos de actores Algunos ejemplos nos ayudarán a aclarar el concepto de actor aplicando las reglas que acabamos de indicar. Un motor eléctrico que es puesto en marcha o parado por un software de tiempo real es un actor, ya que su actividad es autónoma (su rotación sirve para accionar algún dispositivo mecánico), mientras que una impresora no tiene actividad autónoma porque se limita a imprimir la información que le envía un sistema de software (o varios) y, por tanto, su actividad está subordinada a la generación de listados por parte del software. Si la persona A recoge un listado de la impresora y lo entrega a una persona B que hace un resumen manual de la información y lo da a otra persona C, sólo B será actor, ya que A no tiene una actividad autónoma y C no recibe la información directamente del software y, por tanto, el software no “conoce” su existencia. Naturalmente, si A tuviera alguna actividad autónoma sin ninguna relación con el software –por ejemplo, barrer la oficina– no por este motivo sería actor del software.
Un actor es un clasificador (pero a pesar de esto, no es ningún estereotipo estándar del clasificador). Si hay varias entidades exteriores que desempeñan el mismo conjunto de papeles en relación con el software, un único actor las representa todas, de igual manera que una clase representa todos sus objetos posibles (o, dicho de otra forma, estas entidades exteriores serían instancias del actor). El ejemplo de los bibliotecarios (I) Si en una biblioteca pública todos los bibliotecarios pueden utilizar las mismas funciones del software de apoyo a la gestión de la biblioteca, definiremos un único actor para todos. Sin embargo, si hay un bibliotecario que puede realizar algunas funciones que los demás no pueden (como variar la duración de los préstamos), estas funciones se asignarían a otro actor. Hay dos maneras de hacerlo; podéis leer, unas líneas más abajo, la segunda parte de este ejemplo.
Entre actores, es posible establecer relaciones de especialización/generalización con herencia, igual que entre clases. Un actor A que es una especialización de otro B realiza como mínimo todos los papeles de B.
© Editorial UOC
85
Capítulo III. UML (II): el modelo...
Caso especial... Si un proceso se tiene que poner en funcionamiento, automáticamente o no, en una fecha y/o hora determinada, se considera que hay un actor ficticio, por ejemplo “Reloj”, que desempeña este papel. El ejemplo de los bibliotecarios (II) En el ejemplo de los bibliotecarios, el hecho de que haya algunos de ellos (digamos, los jefes de biblioteca) que pueden efectuar todas las funciones (casos de uso, recordémoslo) que desempeñan los demás, más otras propias, hace que sea posible definir un actor Bibliotecario y otro JefeDeBiblioteca, y este último heredará de aquél. Sin embargo, esto mismo se podría expresar de otra forma: haciendo que el actor JefeDeBiblioteca sólo comprendiera los papeles que tienen los jefes de biblioteca y no tienen los demás bibliotecarios. En este caso, evidentemente, no habría herencia, y a los jefes de biblioteca corresponderían dos actores, Bibliotecario y JefeDeBiblioteca.
2.2. Concepto de caso de uso
Un caso de uso documenta una interacción entre el software y un actor o más. Dicha interacción tiene que ser, en principio, una función autónoma dentro del software. Caso especial Si un proceso se tiene que poner en funcionamiento, automáticamente o no, en una fecha y/o hora determinada, se considera que hay un actor ficticio, por ejemplo “Reloj”, que desempeña este papel.
Entre los actores que participan en un caso de uso, conviene distinguir el actor primario del caso de uso, que es el que lo pone en funcionamiento pidiendo la función correspondiente del software. Los casos de uso son un caso particular de los clasificadores; una instancia de un caso de uso es una ejecución de éste con intervención de casos particulares de los actores involucrados. Los casos de uso pueden tener atributos y operaciones que pueden servir para describir el proceso (que también es posible describir de otras maneras, como texto ordinario y diagramas de estados y de actividad).
© Editorial UOC
86
Ingeniería del software
Se pueden hacer descripciones más formales y detalladas de los casos de uso durante el análisis, así como de su implementación “suprimir por medio de diagramas de colaboración o de secuencias”.
Entre los casos de uso y los actores que intervienen se establecen asociaciones (lo cual no tiene nada de especial, ya que unos y otros son clasificadores). El significado de estas asociaciones es el papel del actor en relación con el caso de uso, pero no representan ni la dirección ni el contenido de un eventual flujo de datos entre el software y el actor.
2.3. Relaciones entre casos de uso
Entre los casos de uso se pueden establecer tres tipos de relación: 1) Relaciones de extensión. Se dice que el caso de uso A extiende el B si dentro de B se ejecuta A cuando se cumple una condición determinada. A tiene que ser un caso de uso que también se pueda ejecutar de forma separada de B, y debe tener el mismo actor primario que éste. 2) Relaciones de inclusión. Un caso de uso A está incluido dentro de los casos de uso B, C, etc., si es una parte de proceso común a todos éstos. A no es un caso de uso autónomo, en el sentido de que no tendrá actor primario, sino que siempre será puesto en funcionamiento por uno u otro de los casos de uso que lo incluyen. No obstante, su implementación no puede depender de éstos (Por ejemplo, no puede utilizar sus variables). Por tanto, la inclusión de casos de uso es esencialmente una forma de reutilización. 3) Relaciones de generalización/explotación. Un caso de uso A es una especialización de otro caso de uso B si A realiza todo el proceso de B, más algún proceso específico. Además, hay una forma de relación no tipificada (parecida a las agregaciones entre clases) entre casos de uso que consiste en definir, por ejemplo, un caso de uso que corresponde a todo el sistema, otros que corresponden a todos sus subsistemas, etc.
© Editorial UOC
87
Capítulo III. UML (II): el modelo...
2.4. Notación Tanto para los casos de uso como para los actores, no se utiliza el símbolo de los clasificadores, sino símbolos especiales como los siguientes: • Los casos de uso se representan mediante elipses de trazo continuo. A veces se agrupan todas las elipses dentro de un rectángulo que representa todo el software. • Los actores se representan mediante una figura humana esquemática. • Las relaciones de especialización entre actores y entre casos de uso se representan mediante el mismo tipo de flecha que en el caso de clases. • Las relaciones de extensión y de inclusión entre casos de uso son estereotipos de la dependencia entre clasificadores, y se representan mediante las palabras clave extend e include, respectivamente. Ejemplo de casos de uso y actores con diferentes relaciones Consideremos el ejemplo siguiente:
Los usuarios correspondientes al actor Contable sólo pueden intervenir en los casos de uso Asiento y CreacionCuenta, mientras que el actor JefeContable puede hacer también el caso de uso Correccion. Por tanto, JefeContable es una especialización de Contable. El caso de uso CreacionCuenta extiende el caso de uso Asiento porque cuando se intenta hacer un asiento con una cuenta inexistente es necesario crear esta cuenta. El caso de uso Da-
© Editorial UOC
88
Ingeniería del software
tosCuenta representa el acceso a los datos de una cuenta desde dentro de los casos de uso Asiento y Correccion. A diferencia de CreacionCuenta, no se trata de un caso de uso que pueda ser llevado a cabo de manera directa e independiente por parte un actor y, por tanto, la relación con los casos que utilizan es de inclusión y no de extensión.
3. Los diagramas de interacción
La ejecución de un software orientado a objetos consiste en un encadenamiento de operaciones y de cambios de estado de objetos, el cual, a su vez, consiste en que durante la ejecución de una operación o durante una transición se llaman operaciones sobre otros objetos (o sobre el mismo) y se envían señales que provocan otras transiciones. Así, se puede describir el funcionamiento de los casos de uso y de operaciones complejas. En el UML esta acción se lleva a cabo mediante los denominados diagramas de interacción.
3.1. Interacciones y colaboraciones
Para empezar, tenemos que definir los conceptos de interacción y colaboración.
3.1.1. Interacciones Una interacción es la especificación del comportamiento de un caso de uso u operación en términos de secuencias de intercambio de mensajes entre objetos (o, más exactamente, entre instancias de clasificadores). Estos mensajes contienen estímulos, que pueden ser peticiones de ejecución de operaciones o señales. Un hilo de ejecución es una secuencia de mensajes tal que el primero contiene un estímulo que provoca el envío del segundo, etc. Si el mensaje A ha sido la causa de que se emitiera el mensaje B, se dice que A es el predecesor de B y B, el sucesor de A. Que un mensaje tenga varios sucesores o predecesores quiere decir que hay una bifurcación o confluencia de hilos, respectivamente.
© Editorial UOC
89
Capítulo III. UML (II): el modelo...
3.1.2. Colaboraciones
De la misma forma que para que puedan circular mensajes entre ordenadores es necesario que los ordenadores estén unidos por enlaces de comunicaciones, también debe haber una cierta “infraestructura” para la circulación de mensajes entre objetos (a diferencia del caso de las redes, aquí no se trata de una necesidad física, sino de una necesidad de coherencia entre los diferentes diagramas del UML que describen un software). Esta infraestructura está formada por las clases o clasificadores y las asociaciones entre las mismas, definidas en el modelo estático, así como las asociaciones entre actores y objetos que se obtienen cuando se describen casos de uso mediante interacciones. De acuerdo con esto, para cada interacción se tiene que indicar qué parte del modelo estático utiliza. Si un objeto de la clase A tiene que pedir una operación de un objeto de la clase B, es necesario que estén estas dos clases y que B tenga definida la operación que se pide. Sin embargo, debe haber también una asociación entre estas dos clases y que esté especificada la posibilidad de navegar a través de ella por lo menos desde la clase A hacia la B.
Por tanto, en una colaboración sobre la cual debe tener lugar una interacción determinada, es necesario que figuren todos los clasificadores y asociaciones entre éstos que se utilizarán en la interacción. Sin embargo, de la misma manera que en un caso de uso de las entidades exteriores no nos interesan todos los aspectos, sino sólo el papel que ejecutan en relación con aquel caso de uso, también en una colaboración, más que clases u objetos, lo que se tendrá en cuenta serán sus papeles* respectivos en relación con dicha interacción, y lo mismo es válido para las asociaciones. Resumiendo, una colaboración es un conjunto de papeles de clasificadores o instancias y de papeles de asociaciones entre aquellos que intervienen en una interacción. Una colaboración se puede definir en lo que respecta a clasificadores o por lo que respecta a instancias. *. Conviene no confundir estos papeles con los que desempeñan los clasificadores con respecto a una asociación que los relaciona.
© Editorial UOC
90
Ingeniería del software
La sintaxis de los nombres de los papeles de clasificadores es la que presentamos a continuación: ‘/’ nombre_papel ‘:’ nombre_clasificador ‘[’ nombre_estado ‘] o esta otra: nombre_instancia ‘/’ nombre_papel ‘:’ nombre_clasificador ‘[’ nombre_estado ‘]’ y en el caso de una asociación, tenemos la expresión siguiente: ‘/’ nombre_papel ‘:’ nombre_asociación El nombre_estado corresponde a uno de los estados que pueden tener los objetos de dicho clasificador, y es opcional, juntamente con los corchetes que lo rodean. La primera forma es aplicable tanto a clasificadores como a sus instancias. La representación gráfica de los papeles es igual que la de los clasificadores y asociaciones correspondientes, aunque sólo es necesario especificar los elementos que están modificados –siempre en sentido restrictivo– en la colaboración. En una colaboración pueden figurar varios papeles del mismo clasificador, con nombres de papel diferentes. Los multiobjetos representan un conjunto de objetos de un papel con cardinalidad mayor que 1 dentro de una asociación. Se representan con dos rectángulos superpuestos, de los cuales el de delante está ligeramente desplazado hacia un ángulo para dar la sensación de que hay muchos objetos. Los multiobjetos necesitan dos mensajes para realizar una operación en cada uno de sus objetos: uno sirve para seleccionar el conjunto de enlaces de la asociación que corresponden a los objetos, y el otro mensaje se envía de forma separada a cada objeto individual por medio del enlace respectivo. Estos dos mensajes pueden estar combinados dentro de uno que incluya tanto la interacción como la aplicación de la operación a cada objeto individual.
© Editorial UOC
91
Capítulo III. UML (II): el modelo...
Ejemplo de colaboración Observemos la figura siguiente:
El diagrama estático de partida sería éste (tal vez con otras clases y asociaciones, que no vienen al caso):
Vemos que en el ejemplo de colaboración no se utilizan todos los aspectos que tienen las dos clases y la asociación en el diagrama estático: sólo se usa la navegación en un sentido y el papel préstamos y reservas de la clase Libro se sustituye por el papel más restrictivo préstamos, circunstancia que se refleja en la cardinalidad máxima. Se ha definido una colaboración entre objetos (más exactamente, entre un objeto y un multiobjeto), y al papel que desempeña el objeto unLector se le ha dado el nombre prestatario, mientras que ni el multiobjeto de la clase Libro ni su papel tienen nombre.
3.1.3. Patrones
Una colaboración parametrizada constituye la parte estructural de un patrón orientado a objetos. Los patrones son recetas formales para resolver problemas de diseño que se presentan a menudo, y la descripción de la solución que proponen tiene una parte estructural y otra dinámica. Los patrones se representan como elipses con el contorno discontinuo. Una aplicación de un patrón en un caso particular se representa conectando el sím-
© Editorial UOC
92
Ingeniería del software
bolo del patrón por medio de líneas discontinuas en las clases u objetos que sustituyen las del patrón en esta aplicación.
Ejemplo de aplicación de un patrón Este ejemplo corresponde a una aplicación del patrón Composite, muy conocido, que trata de la implementación de un objeto compuesto, cuyos componentes pueden ser compuestos o no.
En este caso, los objetos compuestos son grupos de datos, y cada uno de sus componentes puede ser un campo (es decir, un dato atómico) u otro grupo de datos. Las clases Campo, Dato y GrupoDeDatos son los argumentos que en este caso concreto sustituyen respectivamente las clases Leaf, Component y Composite, que son los parámetros de la colaboración que describen los aspectos estructurales del patrón.
El UML ofrece dos diagramas para representar una interacción y la colaboración en que se basa: el diagrama de colaboración, que pone énfasis en la descripción de la colaboración, y el de secuencias, que lo pone en la sucesión temporal de los mensajes de la interacción. Hay una tercera manera de describir las interacciones, el diagrama de actividades, que tiene otra orientación.
© Editorial UOC
93
Capítulo III. UML (II): el modelo...
3.2. El diagrama de colaboración El diagrama de colaboración es la representación de una interacción mediante un diagrama estático de la colaboración correspondiente sobre la cual se representan los mensajes de la interacción. Para cada mensaje hay una especificación con la siguiente sintaxis: predecesores guarda expresión_de_secuencia valores_de_retorno signatura A continuación, daremos una explicación de cada elemento del mensaje: • predecesores es la lista de los mensajes predecesores de dicho mensaje que tiene esta forma: ‘(’ número_de_secuencia ‘,’ número_de_secuencia ‘)’ ... ‘/’ El número de secuencia del mensaje que pone en funcionamiento toda la interacción es 1, y los de los mensajes que envía en diferentes momentos el proceso que ha puesto en marcha directamente son 1.1, 1.2, etc., mientras que si el mensaje 1.2 activa un proceso que envía a la vez dos mensajes (y se crean, entonces, dos hilos de ejecución) tendrán los números que se distinguirán por un nombre, como 1.2a y 1.2b. Los mensajes con nombres como 1, 1.3, 1.3.1, 1.3.1.2, etc. se dice que forman una secuencia. Los predecesores que pertenecen a la misma secuencia que el mensaje en cuestión no es preciso mencionarlos.
• guarda es la condición que se tiene que cumplir para que se envíe dicho mensaje (además del hecho de que se hayan recibido los mensajes predecesores). • expresión_de_secuencia tiene esta sintaxis: número_de_secuencia ‘[’ recurrencia ‘]’ ‘,’ número_de_secuencia ‘[’recurrencia ‘]’ ... ‘:’ La recurrencia tiene este formato: ‘*’ ‘[’ cláusula_de iteración ‘]’ Si la iteración es en paralelo, en lugar del asterisco sólo aparece ‘*||’, o: ‘[’ cláusula_de_condición ‘]’
© Editorial UOC
94
Ingeniería del software
Ejemplo de cláusula de iteración La cláusula_de iteración podría ser, pongamos por caso, [x = 1, …, 10]
• La cláusula_de_condición acostumbra a servir para definir ramas de ejecución. Puede haber varios números de secuencia con sus cláusulas de condición respectivas. • valores_de_retorno especifica una lista de nombres de valores retornados –si los hay– como resultado del proceso puesto en marcha por el mensaje. Presenta el formato siguiente: valor_de_retorno ‘,’ valor_de_retorno ... ‘:=’. • signatura está compuesta por el nombre del estímulo y por una lista de argumentos entre paréntesis. Además de los mensajes, se puede indicar la creación y destrucción de objetos y enlaces durante la interacción con las palabras clave new, destroyed, y transient, que equivale a las otras dos y, por tanto, denota que el objeto o enlace ha sido creado y destruido durante la interacción. Tipos de mensajes A continuación, veremos los diferentes tipos de mensajes: a) Mensajes asíncronos. La comunicación asíncrona se produce cuando la clase emisora envía un mensaje al suministrador y se continúa ejecutando sin esperar a que llegue el resultado. La clase receptora, por su parte, no ejecuta la operación inmediatamente, sino que deja la petición en una cola. Se representa mediante una flecha con la punta abierta y cortada horizontalmente.
b) Mensajes síncronos. Sólo se dan cuando el cliente envía un mensaje al suministrador y éste acepta el mensaje. La clase emisora ejecuta el código hasta que envía
© Editorial UOC
95
Capítulo III. UML (II): el modelo...
el mensaje y, después, se espera a recibir el resultado de la operación asociada al mensaje. Se representan mediante una flecha con la punta coloreada que indica el sentido.
Ejemplo de diagrama de colaboración Si usamos la colaboración del “Ejemplo de colaboración”, se ha descrito una interacción en la cual un bibliotecario pide información sobre un objeto de la clase Lector –identificado por su número de carnet– y sus préstamos, mediante un mensaje al objeto unLector que sólo tiene el número de secuencia y la firma de la operación pedida. Durante su ejecución, unLector envía un mensaje al multiobjeto de la clase Libro. Este último mensaje es sincrónico, y del primero no se indica que sea sincrónico o asíncrono porque corresponde a una interacción entre un usuario y el sistema.
3.3. El diagrama de secuencias
A diferencia del diagrama de colaboración, en el diagrama de secuencias no se representan de forma explícita los papeles de asociaciones (quedan implícitos en los mensajes) y se representa explícitamente el orden en el tiempo, e incluso la duración, de los mensajes y de las operaciones que ponen en marcha.
© Editorial UOC
96
Ingeniería del software
El diagrama de secuencias está estructurado según dos dimensiones. El tiempo se representa verticalmente y corre hacia abajo, y no está representado necesariamente a escala. En dirección horizontal, hay franjas verticales sucesivas que corresponden a los diferentes papeles de clasificadores que participan en la interacción; cada papel de clasificador está representado por el símbolo habitual, que encabeza su línea de vida. El orden de los clasificadores de izquierda a derecha no es significativo, aunque la tendencia debe ser que los mensajes circulen de izquierda a derecha y los resultados y respuestas, de derecha a izquierda. La línea de vida simboliza la existencia del papel en un cierto periodo de tiempo. Se representa mediante una línea discontinua vertical que va desde la creación del objeto hasta su destrucción. Si la destrucción no está prevista en el diagrama, entonces la línea de vida irá hasta la parte inferior del mismo, es decir, hasta más allá del último mensaje que se muestra. Si se quiere indicar la destrucción del objeto, entonces el final de la línea de vida irá marcado con una X. Puede ser que durante una parte de la línea de vida haya dos activaciones del objeto a la vez, que no serán concurrentes sino alternativas según una condición que determina que se emita el mensaje que pone en marcha una u otra. Una activación es una parte de la línea de vida durante la cual dicho papel ejecuta una acción, u otros papeles ejecutan otras acciones como consecuencia de una acción ejecutada por el papel. Las activaciones sirven para modelar relaciones de control entre clases y se representan mediante rectángulos alargados verticalmente insertados en las líneas de vida. El inicio y el final del rectángulo coinciden con la llegada del mensaje que pone en marcha la acción y el envío del mensaje de respuesta, respectivamente. Pueden tener etiquetas, que especifican la acción que corresponde al mensaje. Para especificar llamadas recurrentes del mismo papel, se representará una nueva activación desplazada un poco más a la derecha. Los mensajes se indican con flechas iguales a las del diagrama de colaboración, que comienzan en una activación (al principio de ésta o por el medio) y acaban en otra. Su orden de arriba abajo expresa el orden en que se producen en el tiempo. Además, una flecha inclinada (hacia abajo, necesariamente) indica un mensaje de duración no ignorado, o de otro modo la flecha sería horizontal.
© Editorial UOC
97
Capítulo III. UML (II): el modelo...
La especificación de los mensajes es muy parecida a la que hemos visto en el diagrama de colaboración. Las principales diferencias son las siguientes:
• No se indican los números de secuencia, ya que quedan implícitos en el orden temporal de los mensajes y de las activaciones que provocan. • Si hay dos expresiones de secuencia para el mismo mensaje, habrá dos flechas, cada una con la cláusula de condición correspondiente, que saldrán del mismo punto de la activación.
A diferencia del diagrama de colaboración, se pueden indicar los mensajes de retorno al final de una activación, en forma de flechas de línea discontinua y punta abierta.
Ejemplo de diagrama de secuencias Diagrama de secuencias equivalente a diagrama de colaboración. Este ejemplo corresponde al ejemplo de diagrama de colaboración del final del subapartado 4.2:
Observad que no se indican los papeles de los objetos ni los números de secuencia de los mensajes, pero de todas formas queda claro qué mensaje es consecuencia de qué
© Editorial UOC
98
Ingeniería del software
otro. Observad la diferencia entre línea de vida y activación: puesto que los objetos y el actor existían antes de la interacción y continuarán existiendo después, sus líneas de vida (las líneas verticales discontinuas) comienzan antes y acaban después de las activaciones respectivas. Que las flechas de los mensajes sean horizontales quiere decir que se pueden considerar instantáneos, pero en cambio, los procesos tienen una duración no ignorada, ya que tienen una cierta medida en dirección vertical y los mensajes en cascada se encuentran en flechas cada vez más abajo. Ejemplo de diagrama de secuencias con creación y destrucción de objetos y activaciones alternativas. Consideremos el siguiente diagrama de secuencias:
Se trata de añadir o suprimir un campo (dato atómico) contenido dentro de un grupo de datos, según que la función pedida sea a o s, respectivamente. Puesto que un grupo de datos puede estar contenido dentro de otro (una vez o más) se da una activación recursiva de objetos de la clase GrupoDeDatos (naturalmente serán objetos diferentes en cada activación, pero en el diagrama se representa un objeto en general). Los dos mensajes alternativos se producirían en el mismo momento; el hecho de que uno de éstos se represente mediante una. flecha con una parte inclinada es sólo por razones de dibujo. Podéis prestar atención a cómo se representan la creación y la destrucción del objeto campo. La flecha del mensaje de creación (añadir) se supone que coincide con el principio de la activación, el cual lo hace, a su vez, con el principio de la línea de vida. Hay una bifurcación de la línea de vida del ob-
© Editorial UOC
99
Capítulo III. UML (II): el modelo...
jeto de la clase campo desde el comienzo, pero las dos partes no se vuelven a juntar porque cuando se destruye un objeto (observad la X al final de una de sus activaciones), su línea de vida ya no continúa.
4. El diagrama de actividades
El diagrama de actividades se puede considerar una variante tanto del diagrama de estados como de los diagramas de interacción, ya que sirve para describir los estados de una actividad, que es un conjunto de acciones en secuencia y/o concurrentes en el cual intervienen clasificadores.
4.1. Elementos específicos
El diagrama de actividades tiene muchos elementos comunes con los diagramas de colaboración y de estados (objetos, estados, transiciones simples y complejas y seudoestados, acontecimientos, señales, flujos de control). Sus elementos específicos son éstos:
1) Estados de acción, que son un caso particular de los estados, en los cuales no hay un objeto que permanezca en espera de que se produzca un acontecimiento que lo haga salir del mismo, sino que se está desarrollando una acción, que es la acción de entrada del estado. Cuando ésta acabe, se producirá la transición, lo cual significa que un estado de acción no puede tener acciones vinculadas a otros acontecimientos que no sean el de entrada ni, por tanto, transiciones internas. Los estados de acción se representan como un rectángulo en el cual los lados derecho e izquierdo son semicircunferencias, con el nombre de la acción y el de un acontecimiento seguido de “/defer” si durante la acción se puede producir un acontecimiento que no es posible tratar hasta que termine.
© Editorial UOC
100
Ingeniería del software
2) Flujos de objetos, que consisten en que un objeto es creado o cambia de estado en una acción y es utilizado por otra u otras. Los flujos de objetos se representan mediante flechas de punta abierta y línea discontinua. Cuando un flujo de control y un flujo de objeto coinciden, se representa sólo el flujo de objeto. 3) Estados de flujo de objeto, que significan que un objeto, probablemente en un estado convencional determinado, ha pasado a estar disponible al acabar una acción (es decir, al salir de un estado de acción). El objeto, con indicación de su estado, se representa con un flujo de objeto que entra y otro que sale, y el símbolo del objeto en un estado es el mismo utilizado en las colaboraciones. Un objeto puede figurar varias veces en un diagrama, cada vez en un estado diferente. 4) Estados de subactividad, que son un caso particular de los estados compuestos, y corresponden a la ejecución de todo un subdiagrama de actividades. Los estados de subactividad se representan como un estado de acción en cuyo interior hay dos pequeños estados de acción con una transición de uno a otro. 5) Swimlanes son franjas verticales del diagrama que, a diferencia de las del diagrama de secuencias, no corresponden a papeles de clasificadores sino a unidades organizativas responsables de diferentes acciones. Cada estado de acción pertenece a un swimlane, y puede haber transiciones y flujos de objetos de un swimlane a otro. Los swimlanes llevan un nombre en su parte superior y están separados por líneas verticales continuas. 6) Iconos de control, que representan el envío de una señal al acabar un estado de acción y su recepción en otro como entrada. En las transiciones puede haber bifurcaciones y reunificaciones posteriores del flujo de control basadas en condiciones de guarda incompatibles –a menudo complementarias–. Por tanto, no expresan ninguna sincronización, ya que los dos flujos de control son alternativos. En la bifurcación y en la reunificación se ponen rombos en lugar de símbolos de seudoestado (barras gruesas).
Ejemplo de diagrama de actividad
En el ejemplo siguiente se describe la gestión de la compra de ordenadores en una empresa.
© Editorial UOC
101
Capítulo III. UML (II): el modelo...
Si partimos del estado inicial, el departamento que hace la petición realiza la acción Preparación propuesta, de la cual resulta un objeto de la clase Compra en el estado propuesta que entra en la acción Revisión presupuesto, que está a cargo de Control de gestión. Como resultado de esta acción, si no hay presupuesto para la compra (guarda no presupuesto) el departamento que pide pone en marcha la acción Cancelación, con la que se llega al estado final. Si la guarda que se cumple es hay presupuesto, el objeto Compra pasa al estado presupuestada y entra dentro del estado de subactividad Gestión de compra (el cual se supone que está detallado en un diagrama de actividades aparte). Observad que a la vez se envía una señal que hace que el objeto de clase ConexionRed pase al estado acti-
© Editorial UOC
102
Ingeniería del software
vada y que la llegada a este estado produzca una señal que, juntamente con el cumplimiento sucesivo de la actividad Gestión de compra y las acciones Envío y Transporte, permite que se ponga en marcha la acción Recepción, que lleva al estado final.
5. Los diagramas de implementación
Los diagramas de implementación, a diferencia de los estáticos y de los dinámicos, no describen la funcionalidad del software, sino su estructura general con vistas a su construcción, ejecución e instalación. Son dos: • El diagrama de componentes, que muestra cuáles son las diferentes partes del software. • El diagrama de despliegue, que describe la distribución física de las diferentes partes del software en tiempo de ejecución. Se utilizan en el diseño y la implementación.
5.1. El diagrama de componentes
El diagrama de componentes describe la descomposición física del sistema de software (y, eventualmente, de su entorno organizativo) en componentes, a efectos de construcción y funcionamiento. La descomposición del diagrama de componentes se realiza en términos de componentes y de relaciones entre los mismos.
5.1.1. Los componentes
Los componentes identifican objetos físicos que hay en tiempo de ejecución, de compilación o de desarrollo, y tienen identidad propia y una interfaz bien definida.
© Editorial UOC
103
Capítulo III. UML (II): el modelo...
Los componentes incluyen código en cualquiera de sus formatos (código fuente o ejecutable), DLL, imágenes, pero también pueden ser documentos manuales cuando se describen partes no informatizadas de un sistema de información. Ejemplo de componente Un componente podría ser, por ejemplo, un conjunto de clases –ya sea en forma fuente o ejecutable– agrupadas dentro de un paquete de UML o de Java. La interfaz correspondiente constará no de todas las operaciones de alguna clase del paquete que pueden ser pedidas desde otras clases, sino sólo de las que pueden ser pedidas desde fuera del paquete. En un software, puede ser que se encuentren en tiempo de compilación varios paquetes de clases hechas anteriormente que estén en forma ejecutable, que sean necesarios para compilar otros paquetes, éstos de clases nuevas en forma fuente. Después de la compilación, puede ocurrir que las clases resultantes, ahora ya todas en forma ejecutable, se agrupen en paquetes de otro modo (con vistas a la comercialización del software, por ejemplo) y las clases de estos diferentes paquetes colaboren en tiempo de ejecución.
De los componentes, se puede indicar su tipo o una instancia. Los primeros se denominan componentes de tipo y se dan en tiempo de desarrollo o en tiempo de compilación, y los segundos se denominan componentes de instancia y existen en tiempo de ejecución. Un componente se representa mediante tres rectángulos, uno que contiene el identificador del componente (el nombre del tipo y, opcionalmente, el de la instancia, como en las clases y objetos) y dos menores incrustados en el lado izquierdo del primero.
5.1.2. Relaciones entre componentes
En un diagrama de componentes se muestran las diferentes relaciones que se pueden establecer entre componentes y otros componentes, objetos o procesos (objetos activos). En el caso de componentes no informáticos, el significado de la relación es que un componente utiliza la información contenida en el otro. En el caso de
© Editorial UOC
104
Ingeniería del software
componentes de software, se distinguen dos tipos de relaciones, las relaciones en tiempo de desarrollo y las relaciones de llamada: • Las relaciones en tiempo de desarrollo son asociaciones entre componentes que modelan dependencias las cuales se tendrán en cuenta en tiempo de compilación o en tiempo de enlace. • Las relaciones de llamada son asociaciones entre componentes que sirven para modelar llamadas entre componentes, es decir, que un componente –el cliente– utilice servicios de otro –el proveedor–. En tiempo de desarrollo, las relaciones de llamada se establecen entre componentes de tipo, y se representan en los diagramas de componentes. En tiempo de ejecución, se producen entre dos componentes de instancia y se representan en los diagramas de despliegue. Además, un componente puede tener relaciones de agregación y composición con otros componentes y con objetos. En el caso de la composición, los componentes de un componente se pueden representar dentro del mismo. Ejemplo de diagrama de componentes Observad el siguiente diagrama de componentes:
El componente Comp2 utiliza el Comp1 y contiene el componente Comp3 y un objeto de la clase Cl1.
© Editorial UOC
105
Capítulo III. UML (II): el modelo...
5.2. El diagrama de despliegue
El diagrama de despliegue permite (en inglés, deployment) mostrar la arquitectura en tiempo de ejecución del sistema respecto a hardware y software. El diagrama de despliegue se utiliza en el diseño y la implementación. Se pueden distinguir componentes (como los del diagrama de componentes) y nodos, así como las relaciones entre todos éstos. Es más limitado que el diagrama de componentes, en el sentido de que representa la estructura del sistema sólo en tiempo de ejecución, pero no en tiempo de desarrollo o compilación. Sin embargo, resulta más amplio en el sentido de que puede contener más clases de elementos.
5.2.1. Los nodos
Los nodos representan objetos físicos existentes en tiempo de ejecución, sirven para modelar recursos que tienen memoria y capacidad de proceso, y pueden ser tanto ordenadores como dispositivos o personas. Los componentes participan mediante éstos en los procesos. Puede haber nodos de tipo y nodos de instancia. Los nodos se representan mediante paralelípedos rectangulares.
5.2.2. Relaciones dentro del diagrama de despliegue
Entre los nodos se establecen relaciones que significan que existe comunicación entre éstos. Se representan mediante líneas continuas, y se puede hacer con un estereotipo que indica el tipo de comunicación. Un componente o un objeto se puede ejecutar si se utilizan los recursos de un nodo o puede estar contenido en éste. En el primer caso, se da una dependencia con el estereotipo supports; en el segundo, se establece una relación de agregación o composición, que es posible representar de las maneras habituales. Se puede representar que un objeto o componente emigra de un nodo a otro o se transforma en otro. En el primer caso se representa el objeto o componente en
© Editorial UOC
106
Ingeniería del software
los dos nodos, y en los dos casos, la relación entre sí es una dependencia con el estereotipo becomes. Podemos tener asociada una propiedad que indique el tiempo en que se producirá la migración. Además, entre componentes se pueden establecer las mismas relaciones mediante interfaces que en el diagrama de componentes, limitadas, pero en tiempo de ejecución. Ejemplo de diagrama de despliegue Observemos el siguiente diagrama de despliegue:
El nodo Servidor contiene el componente Componente1 y tiene comunicación con el nodo Cliente, que contiene el componente Componente2 y un objeto de Clase1; Componente2 depende de Clase1 de una manera no especificada.
© Editorial UOC
107
Capítulo III. Introducción a la...
Conclusiones
En este capítulo hemos visto el resto de los diagramas que considera el estándar UML. Dichos diagramas son los siguientes: • diagrama de casos de uso, • diagrama de estados, • diagramas de interacción: diagrama de secuencias y diagrama de colaboración, • diagrama de actividad, • diagramas de implementación: diagramas de componentes y diagrama de desarrollo. Hemos visto detalladamente los conceptos y el uso de todos éstos. También hemos tratado las conexiones que se establecen entre estos diagramas, así como entre éstos y el diagrama estático. Así, por ejemplo, los clasificadores figuran en el diagrama estático, el de interacción y el de implementación. Los estados, en el diagrama de estados y en el de actividad; los actores, en el diagrama de casos de uso y en los de interacción que describen la implementación de los casos de uso, etc.
© Editorial UOC
109
Capítulo IV. Recogida y documentación...
Capítulo IV
Recogida y documentación de requisitos
En el capítulo “Introducción a la ingeniería del software OO” se dijo que en esta obra se seguiría el ciclo de vida iterativo e incremental del denominado Rational Unified Process. Se vio también que el primer componente de proceso de cada iteración es la recogida de requisitos, que es la base para los otros componentes de proceso. En este capítulo se verá cómo se realiza la recogida de requisitos en forma documentada, mediante notaciones y conceptos del UML que ya hemos visto. La recogida de requisitos busca obtener información sobre dos aspectos esenciales del software que se desarrolla: 1) Los procesos que debe realizar sobre los datos. 2) La manera en que debe pedir a los usuarios los datos de entrada y qué función del software quieren utilizar en cada momento y presentarles los resultados, que es lo que conocemos como interfaz de usuario del futuro software. Aunque se trata de dos aspectos del software bastante diferentes, puesto que las fuentes de información son las mismas, conviene recoger estos dos tipos de requisitos al mismo tiempo. El uso que se hace de la recogida de requisitos en las diferentes fases del ciclo de vida mencionado es el siguiente: • En la fase de inicio se identifican casi todos los casos de uso, para delimitar el alcance del proyecto, pero sólo se describen detalladamente los más críticos. • Durante la fase de elaboración se describen la gran mayoría de los casos de uso, aunque sólo se implementa una pequeña parte de los mismos.
© Editorial UOC
110
Ingeniería del software
• El resto de los requisitos se describen e implementan en la fase de construcción; en la fase de transición sólo intervienen los eventuales requisitos nuevos o modificados.
1. Los requisitos
Los requisitos son la especificación de lo que debe hacer el software; son descripciones del comportamiento, propiedades y restricciones del software que hay que desarrollar. A menudo se dice que los requisitos deben indicar qué tiene que realizar el software sin decir cómo debe hacerlo; pero esto es demasiado radical, por diferentes razones: • Los desarrolladores de software son técnicos y, tal vez, les resultaría difícil entender unos requisitos extremadamente abstractos. • Está claro que debe haber unas referencias mínimas a la tecnología utilizada. • Finalmente, el software deberá ser compatible con el entorno técnico y organizativo. Los requisitos tienen un doble papel: a) Servir de base para un acuerdo entre los usuarios (más exactamente, la empresa cliente) y los desarrolladores sobre el software que hay que desarrollar. Esto significa que la documentación de los requisitos debe llevarse a cabo de una manera inteligible para los usuarios, que tendrán que revisarlo. b) Los requisitos son la información de partida para desarrollar el software; son la entrada de la etapa siguiente, el análisis.
1.1. Clases de requisitos Existen dos clases de requisitos, los funcionales y los no funcionales.
© Editorial UOC
111
Capítulo IV. Recogida y documentación...
• Los requisitos funcionales describen qué debe realizar el software para sus usuarios: aceptar, verificar y registrar datos, transformarlos, presentarlos, etc. Estos requisitos quedan recogidos en los casos de uso. • Los requisitos no funcionales* no van asociados a casos de uso concretos y consisten en restricciones impuestas por el entorno y la tecnología, especificaciones sobre tiempo de respuesta o volumen de información tratado por unidad de tiempo, requisitos en cuanto a interfaces, extensibilidad, facilidad de mantenimiento, etc.
2. Fuentes de información
Para recoger información de los requisitos que debe cumplir el software, deberemos recurrir a las fuentes de información siguientes: a) Las entrevistas –y eventualmente las encuestas– a los futuros usuarios es importante que vayan acompañadas de la observación directa del trabajo de los mismos. b) La documentación sobre el sistema actual existente. Si el sistema está informatizado, deberán estudiarse los manuales de la aplicación y también los procedimientos manuales que se utilizan. c) Colegas de los usuarios. Es posible que los usuarios estén acostumbrados a realizar su trabajo de la misma manera durante mucho tiempo. Por lo tanto, el hecho de conocer otros puntos de vista les ayudará a salir de esquemas prefijados; pueden hablar con los colegas de los usuarios mismos, los desarrolladores o unos y otros. d) Finalmente, es también muy útil realizar una revisión de sistemas parecidos que existan en el mercado. Los usuarios consideran tan evidente que determinadas funciones forman parte del dominio que creen innecesario mencionarlas, y que, probablemente, están implementadas en todo software parecido que exista. Lo mismo ocurre con las denominadas funciones del sistema, que los usuarios no utilizan *. Los requisitos no funcionales pueden describirse en forma de casos de uso ficticios.
© Editorial UOC
112
Ingeniería del software
en su trabajo normal, pero que son convenientes, y a menudo imprescindibles, para el funcionamiento regular del software: reorganización de las bases de datos, alta y baja de usuarios y mantenimiento de los parámetros y las tablas básicas del software.
3. Pasos de la recogida y documentación de requisitos Los pasos de la recogida y documentación de requisitos son los siguientes: 1) Conocimiento del contexto del futuro software. 2) Recogida y clasificación de los guiones. 3) Identificación de los actores. 4) Identificación de los casos de uso a partir de los guiones. 5) Identificación de relaciones entre casos de uso (extensión, inclusión, especialización). 6) Identificación de las relaciones de especialización entre actores. 7) Documentación de los casos de uso.
3.1. El contexto del software
Los desarrolladores de software que se encargarán de recoger los requisitos generalmente tendrán formación y experiencia informáticas, pero no conocerán la actividad profesional de los usuarios. Si es así, será conveniente que adquieran cierto conocimiento desde el punto de vista organizativo y, como consecuencia, de la terminología que se utiliza; esto es lo que denominamos contexto del software. Hay dos maneras de describir el contexto de un software: • el modelo del dominio, que es la manera simplificada, y • el modelo del negocio, que es una modalidad más detallada. En cualquier caso, hay que elaborar un glosario de los términos más utilizados. Incluso si no se realiza ninguno de los dos modelos, conviene confeccionar el glosario.
© Editorial UOC
113
Capítulo IV. Recogida y documentación...
3.1.1. El modelo del dominio
El modelo del dominio recoge los tipos de objetos –las clases– más importantes. Como objetos importantes, podemos establecer la clasificación siguiente: • Objetos del negocio. Facturas, expedientes, cuentas, etc. • Objetos del mundo real y conceptos relacionados con éstos (cliente, historial de ventas, etc.). • Acontecimientos, como llegadas de trenes, expiración del plazo para pagar una factura, etc. Para realizar el modelo del dominio, se utiliza el diagrama de clases del UML. Al modelizar el contexto, hay que tener presente que se trata de realizar un modelo del entorno del software, y no del software; esto último se realiza dentro de otro componente de proceso, el análisis y diseño.
3.1.2. El modelo del negocio
El modelo del negocio* describe a grandes rasgos los procesos y entidades principales en torno al software. Este modelo describe cada una de las grandes actividades del negocio en términos de casos de uso y de entidades y unidades de trabajo (que son agrupaciones de entidades que tienen un significado para el usuario) que intervienen. Se utilizan el diagrama de casos de uso y el de objetos, y para explicar los casos de uso se pueden usar diagramas de interacción y de actividades. Diferencias del modelo del dominio y el modelo del negocio El modelo del dominio y el modelo del negocio son bastante diferentes; no se puede decir que el modelo del dominio sea la parte del modelo de negocio que considera las entidades del mismo. Las clases del modelo del dominio se han obtenido a partir de un estudio superficial del negocio, mientras que en el modelo del negocio primero se *. Realmente, el término negocio no debe tomarse en sentido literal. El entorno del software puede ser no sólo una organización no lucrativa (o una parte de ésta), sino también un robot, por ejemplo, si el software debe gestionar el funcionamiento de éste.
© Editorial UOC
114
Ingeniería del software
describen, en líneas generales, los casos de uso, después se identifican las entidades que participan en el mismo y, finalmente, estos casos de uso se describen con más detalle, pero siempre teniendo en cuenta los aspectos organizativos más que los informáticos.
3.2. Los guiones
En realidad, los usuarios difícilmente identificarán los casos de uso de una manera explícita y sistemática. Generalmente nos explicarán algunas de las series de operaciones más frecuentes que realizan en su trabajo; esto es lo que se denomina guiones. Los guiones tienen las características siguientes: • Son sesiones que un actor lleva a cabo en relación con el software. • Para un sistema de software existen muchos guiones posibles; es suficiente con describir un subconjunto en el que aparezcan, al menos una vez, todas las funciones que debe tener el software. • Sirven para extraer los casos de uso. Los guiones son la fuente de información principal, ya que expresan las necesidades de los usuarios tal como ellos las ven; conviene que cada guión describa de manera precisa y completa la interacción correspondiente entre el usuario y el software: También es preciso que se indiquen todas las excepciones, casos particulares y precondiciones.
3.3. Identificación de los actores
Como hemos visto, un actor es un papel, o más, de cualquier entidad externa que se prevé que interactuará con el software y le dará información o bien la recibirá. Las entidades externas en cuestión pueden ser personas, máquinas, otros sistemas de software o instantes en el tiempo en los cuales debe ponerse en marcha automáticamente algún proceso.
© Editorial UOC
115
Capítulo IV. Recogida y documentación...
Cada actor tiene un papel para cada caso de uso en el que interviene; un papel es primario si el actor pone en marcha el caso de uso correspondiente. Algunas consideraciones sobre los actores: 1) A una persona, por ejemplo, le pueden corresponder diferentes actores, si es que puede tener diferentes conjuntos de papeles independientes en relación con el software; en realidad, no nos interesa si dos actores pueden ser la misma persona o no. 2) Se supone que los actores no llevan a cabo, en principio, ninguna secuencia de casos de uso determinada, sino que cada actor invoca diferentes casos de uso independientemente en momentos determinados por su actividad exterior en el software. 3) Cada actor debe corresponder al menos a un usuario concreto; así se evita definir actores demasiado abstractos. 4) Es suficiente con identificar los actores, no es necesario describirlos detalladamente. 5) No tiene sentido que dos actores intervengan exactamente en los mismos casos de uso con los mismos papeles. A veces, puede ser útil esta clasificación de los actores: • El usuario final o colectivo de personas que interactuarán directamente con el sistema y utilizarán las funciones de usuario. • El usuario privilegiado o gestor del sistema encargado de definir la forma de funcionamiento del sistema, del que utilizará principalmente sus funciones. • El entorno informático, concepto que agrupa todo lo que se refiere a la interfaz no humana del software.
3.4. Identificación de los casos de uso
Los casos de uso tienen estas características: 1) Son procesos autónomos iniciados por un actor o por otro caso de uso. Dos procesos iniciados por actores diferentes no pueden ser parte del mismo
© Editorial UOC
116
Ingeniería del software
caso de uso, como tampoco pueden serlo los procesos que no sean nunca puestos en marcha directamente por un actor, excepto los casos de uso que formen parte de otros mediante relaciones include. 2) Representan funciones ofrecidas por el software e identifican sus entradas y salidas. Un caso de uso debe proporcionar siempre un resultado definido al actor primario. 3) Describen el qué de estas funciones y no el cómo, excepto las especificaciones no funcionales, a las cuales a veces se puede dar la forma de casos de uso. 4) Pueden servir de base para pruebas de caja negra. 5) Los casos de uso que se describan por primera vez en una iteración determinada deben encajar con los de las iteraciones anteriores; si es indispensable, se pueden modificar estos últimos. Es importante describir todos los casos de uso relativos al software considerado. Sin embargo, dentro de un ciclo de vida iterativo e incremental, se irá haciendo por partes. Los casos de uso se obtienen de los guiones, y se identifican las partes autónomas y eventualmente comunes a diferentes guiones en los que participa un mismo actor; también puede suceder que un caso de uso agrupe diferentes guiones enteros. A cada caso de uso se le da un nombre, que por lo general consta de un verbo y un complemento directo.
3.5. Identificación de las relaciones entre casos de uso
En el subapartado anterior habrán quedado claras las relaciones de extensión, inclusión y generalización entre casos de uso. Con vistas a decidir si una relación entre casos de uso es de un tipo o de otro, se pueden tener en cuenta estas reglas: 1) Una relación de extensión siempre se relaciona con una condición. Así, cuando hay diferentes flujos de proceso posibles o bien casos especiales o errores que deban ser tratados de manera diferente, tendremos relaciones de extensión. No obstante, a pesar de todo, el caso de uso que se ejecuta condicionalmente tiene
© Editorial UOC
117
Capítulo IV. Recogida y documentación...
autonomía en el sentido de que da cierto resultado concreto al actor que lo ha iniciado, que es el mismo que el del caso que se extiende. Ejemplo de casos de uso con el mismo actor Puede ocurrir que deba darse de alta a un cliente que no esté en la situación de uso de registro de un pedido ni en el de planificación de una visita de un vendedor; el actor debería ser, en ambos casos, el que puede dar de alta a clientes.
2) Una relación de inclusión es únicamente un recurso para evitar la descripción de una misma parte de proceso dentro de diferentes casos de uso. Ejemplo de relación de inclusión entre casos de uso Una factura que tiene un error se debe poder rechazar y devolver tanto si la factura es por una compra como por un servicio. Es decir, el caso de uso de rechazo de una factura se incluye tanto dentro del caso de uso de tratamiento de una factura de compra como dentro del tratamiento de una factura de servicio.
Por lo tanto, no es necesario que el caso de uso incluido tenga autonomía ni que sea puesto en marcha directamente por un actor (que, en cualquier caso, sería el mismo que pone en marcha los casos de uso en los cuales se incluye). En caso contrario, probablemente lo mejor será considerar que la relación es de extensión, ya que nada se opone al hecho de que un caso de uso extienda varios con el mismo actor. 3) Una relación de especialización indica que, de los dos casos de uso relacionados, uno es una versión especializada de la otra, en el sentido, por ejemplo, de que el primero se aplica a una subclase de la clase a la cual se aplica el segundo. Ejemplo de relación de especialización El caso de uso de matrícula de un estudiante de nuevo ingreso se puede considerar una especialización del caso de uso de matrícula de un estudiante en general, si el proceso adicional que debe realizarse en el primer caso es un conjunto de operaciones independientes y dispersas. Sin embargo, si este proceso adicional tuviera entidad propia, la relación podría ser de extensión entre el caso general y la parte que sólo se realiza para los estudiantes nuevos.
© Editorial UOC
118
Ingeniería del software
3.6. Identificación de las relaciones de especialización entre actores
El actor A es una especialización del B si A tiene todos los papeles de B (es decir, hace los mismos papeles en relación con los mismos casos de uso) y alguno más. No parece que la identificación de este tipo de relaciones tenga ningún problema.
3.7. La documentación de los casos de uso
Se pueden distinguir dos tipos de documentación de los casos de uso: • documentación textual, • documentación formal.
3.7.1. La documentación textual
La documentación textual se compone de la descripción textual de los casos de uso y el glosario de los términos de la descripción textual.
La descripción textual
Es necesario elaborar una descripción textual de cada caso de uso. Conviene realizarla mediante una plantilla y aplicar sistemáticamente unas normas de formato. A continuación, se describe una manera de realizar la documentación textual de un caso de uso. Establecemos las convenciones siguientes:
• Nombres de actor en negrita, • Otra terminología del usuario en cursiva, • Referencias a otros casos de uso subrayadas.
© Editorial UOC
119
Capítulo IV. Recogida y documentación...
Daremos a la documentación textual la estructura siguiente: • Cabecera. Número y nombre del caso de uso, resumen de la funcionalidad, papel del caso de uso dentro de trabajo del usuario, casos de uso relacionados, actores. • Cuerpo. Precondición y postcondición del sistema, etapas, contenido de las entradas y salidas, alternativas de proceso y excepciones. • Final. Cuestiones que hay que aclarar (las respuestas se incluirán, con autor y fecha, dentro de los comentarios), hipótesis que se realizan sobre aspectos no aclarados, comentarios, cambios. El glosario
Es muy conveniente para unificar la terminología y su interpretación. Se puede extraer del modelo del dominio o del negocio, pero también se puede obtener a partir de entrevistas con usuarios.
3.7.2. La documentación formal Es imprescindible un diagrama de casos de uso que los muestre todos con las relaciones entre éstos y entre los actores. Además, puede ser que para casos de uso concretos convenga utilizar algún otro diagrama como complemento de la descripción textual: diagrama de actividades, de estados o de interacción. Quizá podría crear alguna confusión el hecho de que en el análisis se utilizan también estos diagramas para describir de manera detallada y formalizada los casos de uso; pero hay diferencias importantes: a) En el ámbito de requisitos, la descripción de los casos de uso es principalmente textual, y los diagramas realizan sólo una función complementaria y no se elaboran sistemáticamente para todos los casos (no olvidemos que los usuarios deben entender los requisitos, lo cual obliga a no usar notaciones muy formales). En cambio, en el ámbito de análisis, los diagramas de interacción o de actividades se realizan sistemáticamente para todos los casos de uso como un paso de formalización en términos de objetos antes de su implementación. b) Los diagramas del análisis utilizan las clases definidas en el diagrama estático que se elabora, mientras que los objetos que salen en los diagramas de los
© Editorial UOC
120
Ingeniería del software
requisitos habrán sido identificados en el modelo del dominio o en el modelo del negocio, o simplemente en el momento de realizar el diagrama en el que salen, y por lo tanto son provisionales.
4. La recogida y documentación de requisitos de la interfaz de usuario
En la introducción de este módulo vimos que es necesario recoger tanto los requisitos de funcionalidad como los de interfaz de usuario. Con Weinschenk, Jamar y Yeo podemos hacer esta especificación de los objetivos de la recogida de requisitos de la interfaz de usuario*. Según los autores mencionados, la recogida y documentación de requisitos de la interfaz de usuario consiste en documentar y verificar información sobre los usuarios, su trabajo actual y su visión del trabajo con el software futuro, con vistas al diseño de la interfaz de usuario del nuevo software. Concretamente, se trata de obtener la documentación siguiente: • Restricciones organizativas y técnicas. • Perfiles de los usuarios. • Descripción de las tareas actuales y futuras. • Especificaciones de usabilidad. • Guiones para los casos de uso.
4.1. Concepto de interfaz de usuario
La interfaz de usuario es lo que los usuarios ven del funcionamiento del software. También se denomina interfaz hombre-máquina. *. D. Weinschenk; P. Jamar; S.C. Yeo (1997). GUI Design Essentials. John Wiley & Sons.
© Editorial UOC
121
Capítulo IV. Recogida y documentación...
Ejemplos de interfaces de usuario Los casos más habituales de interfaces son entradas mediante teclado y pantalla y salidas por pantalla e impresora. También se pueden considerar entradas y salidas sonoras y entradas por escáner.
De la interfaz de usuario dependen en gran medida los factores siguientes: • La comodidad del usuario. Afecta a la ansiedad, frustración, confusión, fatiga. • La productividad del usuario. Es mejor en la medida en que sea necesario seleccionar menos teclas y botones, y que los recorridos que deba realizar con el ratón sean más cortos y menos frecuentes. • La imagen del software. Los usuarios juzgan la calidad del software sobre todo a causa de lo que ven más directamente, es decir, a causa de las interfaces. No se dan cuenta de la calidad de la programación, al menos mientras no afecte de manera perceptible al funcionamiento del software; por lo tanto, la interfaz de usuario puede determinar el éxito o el fracaso de un software. Además, una interfaz de usuario inadecuada puede provocar errores del usuario, sobre todo en caso de circunstancias no habituales, en las que el usuario tiene como única guía la interfaz misma. También puede provocar la infrautilización del software (en términos de usuarios potenciales y de funciones disponibles), e incluso su rechazo total.
4.2. Identificación de las restricciones técnicas Hay que determinar si se ha establecido el uso de alguna tecnología, herramienta, plataforma o normativa concretas, y también la disponibilidad de ratón, pantallas de colores y tipos de letra.
4.3. Elaboración de los perfiles de usuario No se puede diseñar correctamente una interfaz de usuario sin saber para quién se hace, ya que un diseño apropiado para un usuario (en sentido colectivo) puede no serlo para otro. Hay que evitar en especial el error de que los de-
© Editorial UOC
122
Ingeniería del software
sarrolladores del software diseñen la interfaz de usuario como si los usuarios fueran ellos mismos, ya que tienen una cultura profesional y unos conocimientos de informática muy diferentes de los de la gran mayoría de los usuarios. Los perfiles de usuario tienen estos aspectos: • Experiencia en torno a hardware y software (ratón, teclado, ventanas, etc.). • Experiencia en aplicaciones del mismo dominio. • Experiencia en el trabajo. • Frecuencia de uso del software y grado de rotación del personal.
4.4. Documentación de las tareas actuales y futuras
De cada tarea hay que recoger los aspectos siguientes: • La tarea en sí, su frecuencia y qué usuarios la realizan. • El entorno en el que se lleva a cabo, especialmente si hay limitaciones de espacio, la iluminación, y si hay suciedad que pueda afectar a algunos dispositivos como los ratones. • Su situación dentro del flujo de tareas, es decir, cuáles la preceden, la siguen o la interrumpen y las interdependencias con otras tareas que obliguen a seguir un orden determinado. • Qué información entra y sale y cuáles son los resultados y hacia dónde van. • Qué documentos y herramientas son necesarios. • Cuáles son los problemas y errores más frecuentes. • Las quejas y sugerencias sobre cómo se realiza la tarea. Esta información no se documenta de manera formalizada. Una tarea o secuencia de tareas se puede representar mediante un diagrama de actividad simplificado en el cual sólo se representen los flujos y los estados de actividad, que corresponderían a operaciones, ya sea manuales o informatizadas. El conjunto de las tareas se puede representar en forma de una tabla que tenga una fila para cada tarea y en la que las columnas correspondan a los aspectos indicados. Obviamente se documentan por separado las tareas actuales y las futuras.
© Editorial UOC
123
Capítulo IV. Recogida y documentación...
4.5. Comparación entre tareas y casos de uso
A pesar de que las fuentes de información para los requerimientos de funcionalidad y de interfaz de usuario son las mismas, la información necesaria no es la misma. Así, al describir los casos de uso desde el punto de vista de la funcionalidad, se pone énfasis en lo que realiza el software, mientras que cuando se describen desde el punto de vista de la interfaz de usuario, lo que interesa más son las acciones que realiza el usuario y en qué condiciones lo hace. Podemos resumir así las diferencias entre tareas y casos de uso: a) Allí donde, desde el punto de vista de un caso de uso, el software presenta determinada información, desde el punto de vista de las tareas el usuario la comprueba y toma una decisión. b) En un caso de uso que tiene diferentes posibilidades, no es necesario indicar la frecuencia de cada una; en una tarea, sí. c) A las tareas puramente manuales no les corresponde ningún caso de uso, y en un caso de uso tampoco se indican las operaciones manuales de una tarea, como poner un disquete antes de empezar un trabajo; en la descripción de una tarea deben tenerse en cuenta, al menos para determinar la duración de la misma. d) Cuando se produce una anomalía, el software se limita a avisar al usuario, según el caso de uso, mientras que según la descripción de la tarea, el usuario debe tomar una decisión y tal vez empezar otra tarea independiente. Por lo tanto, hay que recoger información sobre las mismas funciones desde dos puntos de vista. Una buena manera de recoger requisitos para los dos usos sería que dos desarrolladores realizaran de forma conjunta las entrevistas a los usuarios y que cada uno se interesase por uno de los dos aspectos. Parece claro que es mucho mejor que los dos entrevistadores lleven a cabo una entrevista y no dos entrevistas independientes, por dos motivos: para no hacer perder más tiempo al usuario y para evitar tener dos versiones no coordinadas de las necesidades de usuario.
© Editorial UOC
124
Ingeniería del software
4.6. Especificaciones de usabilidad
Las especificaciones de usabilidad son los requisitos no funcionales relativos a la interfaz de usuario. Las especificaciones de usabilidad se pueden referir a facilidad de utilización o aprendizaje o a rapidez y precisión en la ejecución de las tareas. Conviene expresarlas de manera cuantitativa.
Ejemplos de especificaciones de usabilidad He aquí algunos ejemplos: • Que el 90% de los usuarios que han trabajado al menos un año con el sistema antiguo sean capaces de aprender en una semana las funciones indicadas en una lista, valiéndose sólo de la documentación y la ayuda on-line. • Que el 80% de los usuarios después de una semana de aprendizaje puedan registrar una media de diez facturas en treinta minutos o menos. • Que después de haber practicado dando tres altas de clientes, el 75% de los usuarios pueda dar de alta a diez clientes en veinte minutos o menos y el 90%, en veinticinco minutos o menos.
5. Ejemplo
Utilizaremos un ejemplo de proyecto de software, del que veremos la documentación que se va generando en los pasos sucesivos de las etapas de recogida de requerimientos, análisis y diseño. Por razones didácticas se ha elegido un ejemplo mucho más sencillo que los casos reales. El ejemplo trata de la informatización de la gestión de alquileres de locales comerciales que realiza una agencia inmobiliaria. La información no estructurada del ejemplo está en letra más pequeña, para distinguirla de las explicaciones eventuales.
© Editorial UOC
125
Capítulo IV. Recogida y documentación...
5.1. Información inicial
Éste es el resumen de la primera entrevista que tuvo el equipo de desarrollo del software con el representante de la agencia inmobiliaria: La agencia inmobiliaria (que desde ahora se denominará simplemente la agencia) alquila locales comerciales, que pueden ser tiendas-almacén, oficinas o inmuebles. Los inmuebles son edificios que es posible alquilar enteros o por oficinas y tiendas-almacén individuales. Además, hay unos locales, denominados polivalentes, que pueden considerarse tanto oficinas como almacén. Los propietarios de los locales pueden ser particulares o empresas. El propietario puede cancelar en cualquier momento la oferta de su local, pero mientras no lo haga no lo puede alquilar por su cuenta y está obligado a aceptar al arrendatario que proponga la agencia si cumple las condiciones estipuladas; entonces la agencia prepara el contrato de alquiler, que siempre es por un tiempo determinado. Cuando se cumple el plazo de preaviso de la renovación o no del contrato de alquiler, si hay renovación la agencia prepara el nuevo contrato y si no hay renovación o el arrendatario cancela el contrato antes del plazo mencionado, la agencia propone al propietario buscarle otro arrendatario. Otro servicio que realiza la agencia es recibir peticiones de alquiler de locales con características determinadas (situación y superficie, principalmente) y entonces se buscan locales que las tengan, entre los que alquila la agencia y, si es necesario, otras agencias. Cuando encuentra uno conveniente, se propone al propietario que se convierta en cliente y, si acepta, se prepara el contrato.
5.2. Modelo del dominio
A simple vista se identifican los objetos o clases ‘local’, ‘propietario’, ‘arrendatario’ y ‘contrato de alquiler’ (objetos del mundo exterior), ‘petición de alquiler de local’ (objeto del dominio) y ‘plazo de preaviso de fin de alquiler’ (acontecimiento). Se han puesto algunos atributos a las clases de manera orientativa (sin tipo, o reuniendo en uno lo que pueden ser varios, como es el caso de situación).
© Editorial UOC
126
Ingeniería del software
No es necesario que los nombres de los atributos, e incluso de las clases, respeten las restricciones de algún lenguaje, porque este diagrama no se utilizará para etapas posteriores.
5.3. Modelo del negocio
Para elaborar el modelo del negocio, sería necesaria más información con vistas a elaborar unos primeros casos de uso. La información adicional es la siguiente: Cuando un propietario ofrece un local, es entrevistado por un agente que le pide los datos identificativos y la dirección, superficie, características y restricciones (que el arrendatario no pueda poner un bar de copas, por ejemplo) del local, e introduce estos datos en el ordenador; después, un inspector visita el local y realiza un informe, a partir del cual fija el precio del alquiler y los usos para los que es adecuado. Cuando se produce una petición de alquiler, un vendedor entrevista al eventual arrendatario e introduce en el ordenador los datos y las características del local que pide; cuando se realiza un contrato de alquiler, el vendedor introduce los datos del arrendatario y del contrato.
© Editorial UOC
127
Capítulo IV. Recogida y documentación...
El diagrama de casos de uso del modelo del negocio es el siguiente:
Mediante los diagramas de colaboración, identificamos los objetos que utilizan los casos de uso anteriores:
© Editorial UOC
128
Ingeniería del software
El diagrama de objetos del modelo del negocio es el siguiente:
5.4. El glosario del modelo del negocio
A continuación, se presenta el glosario del modelo de negocio. Agencia: agencia inmobiliaria X, dedicada a la intermediación en el alquiler de locales comerciales. Agente: empleado de la agencia que entrevista a los propietarios. Arrendatario: persona o empresa que alquila un local comercial. Arrendatario eventual: persona que pide a la agencia que le busque un local con unas determinadas características para alquilarlo con vistas a un uso concreto. Código del local: dato que identifica un local, formado por el código de la zona, el tipo de local y un número correlativo. Contrato: contrato legal de alquiler de un local, firmado por el propietario y el arrendatario.
© Editorial UOC
129
Capítulo IV. Recogida y documentación...
Informe: reporte que elabora un inspector de la agencia sobre un local después de visitarlo. Inspector: empleado de la agencia que visita los locales antes de ofrecerlos en alquiler. Local: inmueble o parte de éste que se alquila para usos comerciales, es decir, cualquier uso excepto de vivienda o industria. Puede ser inmueble, oficina, tienda-almacén o polivalente. Precio: importe mensual del alquiler de un local. Propietario: persona o empresa que tiene el título de propiedad del local. Los clientes de la agencia son los propietarios de los locales que alquila. Vendedor: empleado de la agencia que entrevista a los arrendatarios y arrendatarios eventuales, busca locales adecuados para estos últimos y prepara los contratos.
5.5. Los guiones
Se han encontrado tres guiones: El guión del agente Llega un cliente y se le piden los datos del local que quiere alquilar: dirección, tipo, superficie, características, restricciones, el volumen si se trata de una tienda-almacén y las características polivalentes si es un polivalente, y se le asigna un código que contiene la zona, el tipo y un número correlativo. Si el propietario no estaba introducido para un local anterior, hay que dar la razón social o los apellidos y nombre –según se trate de una empresa o de un particular–, la dirección, el teléfono y el NIF. Una vez añadido el local, no se puede alquilar aún, sino que queda pendiente de inspección. El guión del inspector La inspección consiste en una vista previa del inspector al local. El inspector examina diferentes aspectos del local (forma, accesibilidad, instalaciones, estado de conservación, visibilidad, etc.) con el objetivo de determinar el precio de alquiler y los usos posibles. El inspector mismo introduce esta información.
© Editorial UOC
130
Ingeniería del software
El guión del vendedor Una vez que se le ha puesto precio, el local está pendiente de alquilar; se anuncia en la prensa y los vendedores lo ofrecen a los arrendatarios eventuales. Cuando llega un arrendatario eventual, le atiende un vendedor que lo entrevista e introduce sus datos (apellidos y nombre, NIF, teléfono, dirección, tipo de local que desea, zona o zonas, superficie mínima y diferentes requisitos). A continuación, el vendedor lleva a cabo una búsqueda entre los locales pendientes de alquilar; si encuentra locales adecuados, le comenta las características (excepto la dirección del local y los datos del propietario); si al arrendatario eventual le interesa algún local, se marca el local como comprometido y se pone en marcha la preparación del contrato, que empieza con el aviso al propietario. Si entre los locales que la agencia ofrece no hay ninguno apropiado, la agencia busca más locales por otros medios y, cuando encuentra uno conveniente, ofrece al propietario presentarle un alquiler a cambio de que el propietario se convierta en cliente de la agencia.
5.6. Casos de uso
A lo largo de los subapartados siguientes realizaremos la identificación de los casos de uso correspondiente a la situación planteada.
5.6.1. Actores
Los actores son tres: agente, inspector y vendedor, que son usuarios finales directos del sistema. En cambio, no son actores ni los propietarios ni los arrendatarios o arrendatarios eventuales, ya que no tienen interacción con el sistema, sino que toda la relación que tienen es mediante los agentes y los vendedores (por lo tanto, el software no los “ve”). El agente tiene dos papeles, ya que añade locales, por un lado, y propietarios, por otro. El vendedor tiene cuatro, ya que introduce arrendatarios, arrendatarios eventuales y contratos, y busca locales. Todos estos papeles son primarios. Los tres actores son independientes. Entre ellos no hay ninguna relación de especialización, ya que, como veremos a continuación, no hay ningún caso de uso que puedan hacer dos de los actores.
© Editorial UOC
131
Capítulo IV. Recogida y documentación...
5.6.2. Diagrama de casos de uso
A continuación, vemos el diagrama de casos de uso relacionado con el ejemplo:
5.6.3. Documentación textual
Se utilizan las convenciones y la estructura descritas antes, pero, como sucede también en la realidad, no todos los casos de uso tienen todos los datos posibles (por ejemplo, descomposición en etapas). No se proporciona el glosario de los casos de uso porque, por la sencillez del caso, coincidiría con el glosario del modelo del negocio. Asimismo, en los casos reales generalmente se habrán introducido términos nuevos en las descripciones de los casos de uso. Caso de uso número 1: ‘Añadir local’ Resumen de la funcionalidad: añade un local a la base de datos.
© Editorial UOC
132
Ingeniería del software
Papel en el trabajo del usuario: es el caso de uso principal del trabajo de los agentes. Actores: agente. Casos de uso relacionados: Añadir propietario, Introducir informe, Introducir contrato. Precondición: el local no existe en la base de datos. Postcondición: el local está incorporado en la base de datos. El agente introduce los datos del local: un código del local –que contiene la zona, el tipo (tienda-almacén, oficina, polivalente o inmueble entero), y un número correlativo–, la dirección, la superficie, un texto de características, otro de restricciones, el NIF del propietario, el volumen si es tienda-almacén y el texto de características polivalentes si es un polivalente. Alternativas de proceso y excepciones: si el propietario no estaba introducido, hay que añadirlo según el caso de uso Añadir propietario. Cuestiones que hay que aclarar: • ¿Hay que registrar qué agente ha añadido el local? Respuesta: sí; el nombre del agente se toma de una lista. Caso de uso número 2: ‘Añadir propietario’ Resumen de la funcionalidad: añade un propietario a la base de datos. Papel en el trabajo del usuario: es un caso de uso esporádico en el trabajo de los agentes. Actores: agente. Casos de uso relacionados: Añadir local, Introducir contrato. Precondición: el propietario no existe en la base de datos. Postcondición: el propietario está incorporado en la base de datos. El agente introduce los datos del propietario: el NIF, la razón social si es una empresa o los apellidos y nombre si es un particular, la dirección y el teléfono. Este caso de uso puede ser ejecutado independientemente o ser llamado desde el caso de uso Añadir local. Caso de uso número 3: ‘Introducir informe’ Resumen de la funcionalidad : añade el informe del inspector a un local.
© Editorial UOC
133
Capítulo IV. Recogida y documentación...
Papel en el trabajo del usuario: es el caso de uso único en el trabajo de los inspectores. Actores: inspector. Casos de uso relacionados: Añadir local, Introducir contrato. Precondición: el local está introducido en la base, pero aún no tiene el informe y, por lo tanto, no está disponible para alquilar. Postcondición: el local tiene incorporado el informe y está disponible para alquilar. El inspector introduce el código del local y después los textos sobre cada uno de los aspectos del local: la forma, la accesibilidad, las instalaciones, el estado de conservación, la visibilidad y diferentes aspectos; también introduce los usos recomendados (los toma de una lista) y el precio. Además, puede modificar la dirección, la superficie, el tipo y el texto de características. Cuestiones que hay que aclarar: • ¿Hay que registrar qué inspector ha realizado el informe? Respuesta: sí; el nombre del inspector se toma de una lista. Caso de uso número 4: ‘Introducir contrato’ Resumen de la funcionalidad: introduce en la base de datos la información necesaria para preparar un contrato. Papel en el trabajo del usuario: pertenece a la parte principal del trabajo de los vendedores. Casos de uso relacionados: Añadir arrendatario. Precondición: el local está disponible para alquilar. Potscondición: el local está alquilado. El vendedor introduce el código del local y después el NIF del arrendatario; después se añaden las fechas de inicio y de final del contrato. Alternativas de proceso y excepciones: si el arrendatario no estaba introducido, se le añade según el caso de uso Añadir arrendatario. Cuestiones que es preciso aclarar: • ¿Hay que registrar qué vendedor ha introducido el contrato? Respuesta: sí, el nombre del vendedor se toma de una lista.
© Editorial UOC
134
Ingeniería del software
• ¿Hay que imprimir directamente el contrato? Respuesta: no, pero deben imprimirse los datos del propietario, arrendatario, local y fecha de inicio y final del contrato con el objetivo de preparar el contrato fuera de la aplicación. Caso de uso número 5: ‘Añadir arrendatario’ Resumen de la funcionalidad: añade los datos de un arrendatario en la base de datos. Papel en el trabajo del usuario: lo utilizan ocasionalmente los vendedores como paso previo a la introducción de un contrato. Actores: vendedor. Casos de uso relacionados: Añadir eventualmente arrendatario, Añadir contrato. Precondición: el arrendatario no existe en la base de datos. Postcondición: el arrendatario está incorporado en la base de datos y, por lo tanto, puede figurar en un contrato. El vendedor introduce los datos del arrendatario: el NIF, los apellidos y nombre (o la razón social, si es una empresa), el teléfono y la dirección. Caso de uso número 6: ‘Añadir arrendatario eventual’ Resumen de la funcionalidad: añade los datos de un arrendatario eventual en la base de datos. Papel en el trabajo del usuario: lo utilizan ocasionalmente los vendedores como paso previo a la búsqueda de locales que puedan convenir al arrendatario eventual . Actores: vendedor. Casos de uso relacionados: Añadir arrendatario, Añadir contrato. Precondición: el arrendatario eventual no existe en la base de datos. Postcondición: el arrendatario eventual está incorporado a la base de datos y, por lo tanto, puede figurar en un contrato. Es parecido al caso de uso Añadir arrendatario, excepto que, además, el vendedor introduce los datos siguientes: el tipo de local, la zona o zonas deseadas, la superficie mínima y varios requisitos. Caso de uso de número 7: ‘Buscar locales’ Resumen de la funcionalidad: busca los locales que cumplen determinadas condiciones.
© Editorial UOC
135
Capítulo IV. Recogida y documentación...
Papel en el trabajo del usuario: lo utilizan ocasionalmente los vendedores para la búsqueda de locales que puedan convenir al arrendatario eventual . Actores: vendedor. Casos de uso relacionados: ninguno. Precondición: ninguna. Postcondición: ninguna, al ser una consulta. Busca todos los locales que cumplen unas condiciones especificadas antes de la ejecución en términos de tipo, zona y superficie y obtiene una lista de la que se pueden seleccionar locales uno por uno para ver toda la información o bien toda menos la dirección y el NIF del propietario. Otros requisitos La información sobre propietarios, arrendatarios, locales y contratos hay que poderla consultar y modificar y, la que ya no se utilice, borrarla.
5.7. Requisitos de la interfaz de usuario Aquí determinaremos los requisitos que debe cumplir la interfaz de usuario.
5.7.1. Perfiles de usuarios De entrada, se realiza una explicación de los perfiles de los usuarios. Todos los usuarios conocen a fondo su trabajo. Los agentes y los vendedores están acostumbrados a utilizar ordenadores, pero los inspectores no mucho. Ningún usuario ha utilizado ninguna aplicación parecida. La rotación del personal es muy baja. Todas las funciones del software se realizarán muy a menudo.
5.7.2. Documentación de las tareas futuras Aquí sólo se incluye la documentación de las tareas futuras. La de las tareas antiguas se realizaría de la misma manera.
© Editorial UOC
136
Ingeniería del software
Añadir un local El agente teclea la dirección y superficie del local (en m 2) y los textos de características y restricciones. Respecto al código del local, la zona y el tipo se eligen de las listas respectivas. El sistema lo asigna automáticamente el número correlativo. El agente teclea también el NIF del usuario y, si no existe, el agente puede optar entre cambiarlo y añadir un nuevo propietario con aquel NIF. Cuando se añade un propietario, el NIF es el que se había dado con los datos del local. El agente teclea la dirección, el teléfono y el nombre y apellidos o la razón social. Introducir un informe El inspector trae escrita en un impreso la información que ha recogido durante la visita. Para introducirla en el ordenador, teclea en primer lugar el código del local; la comprueba y la puede modificar, excepto el código del local y el texto de restricciones. Teclea los campos textuales de forma, accesibilidad, instalaciones, visibilidad y precio, y selecciona de una lista un valor para el estado de conservación, y de otra lista, el valor o valores de los usos posibles del local. Introducir un contrato El vendedor introduce el código del local y le sale toda la información sobre el mismo; la comprueba y si había algún error, cancela la tarea, y si no hay ninguno, introduce el NIF del arrendatario. Si el arrendatario existe, salen todos los datos y el vendedor puede cancelar la tarea o continuar, y modificar los datos o no hacerlo; si no existe, salen los datos en blanco y puede introducirlos o cancelar la tarea; si introduce los datos y los confirma, está en el mismo punto que si hubiera encontrado un arrendatario inicialmente. Si continúa, introduce la fecha de inicio y la fecha de la vigencia del contrato. Entonces puede confirmar la tarea o cancelarla; si la confirma, se imprimen los datos del contrato, que son éstos: • del propietario, los apellidos y nombre o la razón social, el NIF y la dirección; • del local, la dirección; • del arrendatario, los apellidos y nombre o la razón social, el NIF y la dirección; • los datos de inicio y de fin de la vigencia. Introducir un arrendatario eventual El vendedor introduce el NIF y puede confirmar o cancelar la tarea; si el NIF ya existe en la base de datos, sale toda la información del arrendatario eventual, que puede ser modificada, y si no, salen los mismos datos pero vacíos. Estos datos son el apellido y nombre o la razón social, la dirección, el teléfono, el tipo de local y las zonas desea-
© Editorial UOC
137
Capítulo IV. Recogida y documentación...
das, la superficie mínima en m 2 y el campo de diferentes requisitos. El tipo de local y las zonas se eligen de las listas respectivas, mientras que el resto de los datos se teclea. Buscar locales Se pueden buscar locales si se da alguno de los datos siguientes: • • • • •
el código del local; la zona; el NIF del propietario; el NIF del arrendatario o arrendatario eventual; la superficie mínima (en m2).
Sólo puede darse uno de estos valores, excepto la zona y la superficie mínima, que pueden darse a la vez. Cuando se da el NIF de un arrendatario, salen los locales que tiene alquilados, y si es un arrendatario eventual, salen los locales que cumplen sus requisitos en cuanto a superficie y zona. Se puede elegir entre que salgan todos los locales o sólo los disponibles, y que salgan todos los datos de los locales o todos excepto el NIF de propietario y la dirección. La lista sale en pantalla y opcionalmente se puede imprimir.
En la tabla siguiente resumimos todos estos aspectos:
© Editorial UOC
138
Ingeniería del software
5.7.3. Requisitos de usabilidad
Los agentes e inspectores deben ser capaces de utilizar el sistema después de una explicación y práctica de una hora, y los vendedores después de una explicación y práctica de dos horas.
© Editorial UOC
139
Capítulo IV. Introducción a la...
Conclusiones
Se ha visto un procedimiento para recoger y documentar los requisitos del software que se quiere desarrollar desde sus dos vertientes: los procesos y la interfaz de usuario. Antes de proceder a la recogida de requisitos del software, los desarrolladores deben adquirir y documentar un cierto conocimiento del entorno en que se utilizará el software, aspecto que se consigue realizando el modelo del dominio o el modelo del negocio (más extenso, como sabemos). A pesar de que hay diferentes fuentes de donde se puede extraer información útil con el objetivo de establecer los requisitos, la fuente más importante son los futuros usuarios, gracias a sus entrevistas. En cada entrevista conviene establecer tanto los requisitos en cuanto a proceso como los requisitos en cuanto a interfaz de usuario, que sirven para especificar los casos de uso y las tareas respectivamente. Se ha visto un ejemplo de recogida y documentación de requisitos. De la misma manera que en un caso real, no se ha dado toda la información de una sola vez, sino que se supone que se ha completado durante la elaboración de la documentación y en forma de respuesta a dudas que se presentaban entonces. También se puede ver que la documentación de las tareas incluye aspectos que no abarcan la documentación de los casos de uso y viceversa, ya que la finalidad con que se elaboran es diferente, pero no deberían existir contradicciones entre las dos, pues serían errores.
© Editorial UOC
141
Capítulo V. Análisis orientado a objetos
Capítulo V
Análisis orientado a objetos
Este capítulo trata del análisis del software con técnicas orientadas a objetos, aplicando las notaciones y conceptos del UML y siguiendo el ciclo de vida del Rational Unified Process. Dentro de este ciclo de vida, el análisis y el diseño constituyen un solo componente del proceso, pero nosotros los consideraremos dos etapas diferentes, por razones que se irán explicando a lo largo del capítulo. En los apartados siguientes se verá detalladamente el papel del análisis en relación con la etapa que lo precede, la recogida y documentación de requisitos, y la que lo sigue, el diseño (siempre con la condición de que consideramos que el desarrollo de software no es un proceso lineal, sino que el ciclo de vida es iterativo e incremental, y que, por lo tanto, sus etapas se repiten para diferentes partes del software hasta completarlo). Aquí decimos, no obstante, que el análisis es la primera etapa del desarrollo del software propiamente dicho, y que consiste en traducir los requisitos a una forma más adecuada para ser la base de partida de este desarrollo. En el análisis distinguiremos los pasos siguientes:
• La revisión de los casos de uso, • La identificación de las clases de análisis, • La identificación de las relaciones entre clases, • La especificación formal de los casos de uso, • El análisis de la interfaz de usuario.
© Editorial UOC
142
Ingeniería del software
1. El papel del análisis
1.1. La relación entre la recogida de requisitos y el análisis La etapa de recogida y documentación de requisitos establece los requisitos del futuro sistema de software con suficiente detalle para que se pueda empezar a desarrollar. Se supone que hay un acuerdo entre los usuarios (o sus supuestos representantes) y los desarrolladores del software sobre estos requisitos; esto significa que los requisitos están expresados de una manera poco formalizada, ya que, de otra forma, serían inteligibles sólo por profesionales del desarrollo del software. Sin embargo, unos requisitos en esta forma no son una buena base para construir un software de manera sistemática. Por lo tanto, un primer cometido del análisis es el de traducir los requisitos a un lenguaje más formal, que en el método que seguimos son los modelos y diagramas del UML; así se obtiene lo que se denomina modelo del análisis. ¿Cuáles han sido los productos de la etapa de recogida y documentación de requisitos? Básicamente, la descripción de las funciones del software en forma de casos de uso, por un lado, y de tareas de los usuarios, por el otro; el modelo del dominio o el modelo del negocio y el glosario son sólo documentos previos o, como mucho, complementarios, de estos dos. Ahora bien, un desarrollo orientado a objetos debe utilizar un formalismo de clases y objetos que en los casos de uso y las tareas no aparece todavía. Por lo tanto, un segundo cometido de la etapa de análisis será la identificación de unas clases fundamentales que serán la base de la implementación del software. Un tercer cometido será la expresión de los casos de uso en términos de estas clases.
1.2. La relación entre el análisis y el diseño Tanto en el análisis como en el diseño se describe el futuro software de manera orientada a objetos. La diferencia fundamental es el hecho de que en el análisis se describe el funcionamiento del futuro software, sin entrar en la problemática de la implementación.
© Editorial UOC
143
Capítulo V. Análisis orientado a objetos
En realidad, el análisis se puede realizar sin tener en cuenta en qué lenguaje de software se implementará, e incluso es muy conveniente hacerlo de este modo (excepto, tal vez, los nombres de clases, atributos y operaciones). Asimismo, existe un alto grado de continuidad entre el análisis y el diseño, ya que la mayoría de las definiciones de clases del análisis se utilizan después en el diseño; en los métodos de desarrollo no orientados a objetos, en cambio, se utilizan modelos diferentes al análisis y el diseño.
1.3. La utilidad del análisis
Jacobson, Booch y Rumbaugh mencionan cuatro razones que pueden justificar la elaboración de una documentación de análisis separada de la del diseño:* 1) Es posible analizar todo el software con un coste relativamente bajo y después implementarlo por partes de una manera coherente, ya que el análisis habrá proporcionado una perspectiva global. 2) La documentación del análisis ofrece una visión general del software, pero sin llegar a los detalles de la implementación, que es muy útil para adquirir rápidamente un conocimiento del mismo. 3) De sistemas de software en los cuales la seguridad es crítica, se pueden realizar varias implementaciones partiendo de un único análisis. Lo mismo se puede hacer si se desea encargar varias implementaciones para quedarse con la mejor. 4) Para conformar de nuevo un sistema antiguo con tecnología actual, la descripción de éste realizada mediante análisis puede ser una base de partida mucho más conveniente que la implementación existente, en la que aparecen muchos más detalles que no hay que tener en cuenta. El uso que se lleva a cabo del análisis en las diferentes fases del ciclo de vida del Rational Unified Process puede ser uno de estos tres: • El modelo del análisis se va actualizando y se utiliza en todo el ciclo de vida. *. I. Jacobson; G. Booch; J. Rumbaugh (2000). El proceso unificado de desarrollo de software. AddisonWesley.
© Editorial UOC
144
Ingeniería del software
• El modelo de análisis se considera un resultado transitorio y cuando se entra de lleno en el diseño y la programación se abandona; los problemas de análisis que aparezcan se resuelven en el ámbito de diseño y programación. • No hay modelo de análisis, o bien se integra con la documentación de los requisitos –y entonces es necesario que ésta sea mucho más formal, lo cual dificulta que la puedan entender la mayoría de los usuarios– o bien se pasa directamente de los requisitos al diseño. Esto último significa ponerse a resolver un problema que no ha sido especificado formalmente y, por lo tanto, de manera suficientemente clara y coherente, lo cual sólo podría ser aconsejable en casos extremadamente sencillos.
2. Paquetes de análisis y paquetes de servicios
Por poca envergadura que tenga un proyecto de software, será necesario dividir la documentación en paquetes de UML, cada uno de los cuales contendrá clases, casos de uso u otros elementos del UML. En una división bien hecha, los paquetes cumplirán dos condiciones: 1) Serán coherentes, es decir, los elementos del mismo paquete estarán fuertemente relacionados. 2) Serán poco dependientes unos de otros, es decir, existirán pocas conexiones entre elementos de paquetes distintos. Se distinguen dos niveles de paquetes: paquetes de análisis y paquetes de servicios; unos y otros se basan en la funcionalidad (es decir, en ningún caso en los requisitos no funcionales). Cada paquete de servicio está incluido dentro de un solo paquete de análisis. Una vez descompuesto el software en paquetes, o un paquete de análisis en paquetes de servicio, conviene identificar las dependencias entre paquetes. Si se considera que hay demasiados, se cambia la descomposición.
© Editorial UOC
145
Capítulo V. Análisis orientado a objetos
2.1. Los paquetes de análisis
Los paquetes de análisis constituyen una división del sistema de software que tiene sentido desde el punto de vista de los expertos en el dominio. Cada paquete de análisis corresponde a uno o varios subsistemas enteros, y puede servir para repartir el trabajo del análisis entre varias personas o equipos. La descomposición del software en paquetes se establece cuando uno tiene una idea que considera suficientemente fiable de la cantidad de trabajo y del número y la complejidad de los diagramas, situación a la cual se puede haber llegado tanto al principio de la etapa de análisis como un tiempo después. Se pueden asignar paquetes separados a los grandes procesos del negocio o bien a los actores primarios, y en cualquier caso, los casos de uso entre los que hay relaciones de extensión, inclusión o generalización deben asignarse al mismo paquete. Puede suceder que una clase (generalmente una clase de entidad) se utilice en más de un paquete; si hay diferentes clases compartidas por los mismos paquetes, se puede hacer un paquete aparte con éstas, mientras que si sólo hay una clase, se la puede dejar fuera de los paquetes. También se puede desarrollar la clase dentro de un paquete –en el que se creen los objetos, por ejemplo– mientras que los otros la utilizarían. En cualquier caso, entre los paquetes que utilizan la misma clase o clases y la clase o paquete mencionado se establecen las relaciones de dependencia correspondientes.
2.2. Los paquetes de servicios
Los paquetes de servicios* son subdivisiones de los paquetes de análisis desde un punto de vista que podríamos denominar comercial, es decir, son opciones separadas en lo que respecta a las organizaciones clientes. Ya sabemos que los casos de uso son autónomos, en el sentido de que cada uno lo entrega de manera independiente al actor primario respectivo. Asimismo, hay casos de uso relacionados en el sentido de que no es posible poner en marcha uno si antes no se ha llevado a cabo otro (por ejemplo, no se *. Podríamos decir que los paquetes de servicios son opciones de catálogo comercial.
© Editorial UOC
146
Ingeniería del software
puede emitir una factura para un cliente si antes no se ha creado el pedido correspondiente); en estas circunstancias, es lógico que ambos casos formen parte del mismo paquete de servicios. En cambio, un caso de uso relativo a la obtención de estadísticas sobre el tiempo transcurrido entre la creación de un pedido y la emisión de la factura correspondiente podría formar parte de un paquete de servicios opcional de estadísticas, que unas empresas clientes del software comprarían y otras, no (aunque el actor de los tres casos de uso fuera el mismo). Los paquetes de servicios presentan las características siguientes: • Comprenden casos de uso relacionados. • Generalmente, sus casos de uso tienen que ver sólo con un actor o, en cualquier caso, con pocos. • Son indivisibles, en el sentido de que un cliente o tiene un paquete de servicios completo, o no lo tiene. • Pueden ser incompatibles o, por el contrario, uno puede necesitar de otro o de varios. • En un caso de uso pueden intervenir varios paquetes de servicios. • Existen muy pocas relaciones de dependencia entre elementos de paquetes de servicios diferentes y, en consecuencia, se pueden analizar, diseñar y más adelante mantener de manera totalmente independiente o casi. • Se pueden reutilizar, por lo menos entre diferentes configuraciones del sistema de software. La descomposición de los paquetes de análisis en paquetes de servicios se realiza asignando un paquete de servicios a cada conjunto de casos de uso opcional.
3. Revisión de los casos de uso
La base de partida para el análisis es la documentación sobre los casos de uso elaborada en la etapa anterior. Por lo tanto, conviene que ésta sea precisa y detallada. Si la documentación se había realizado con el objetivo principal de ser
© Editorial UOC
147
Capítulo V. Análisis orientado a objetos
la base de un acuerdo entre usuarios y desarrolladores, puede ocurrir que no cumpla estas condiciones y será necesario revisarla. Podrían existir carencias como que no se muestren las relaciones entre casos de uso o que haya algunas ambigüedades en la terminología utilizada en las descripciones textuales. Si no se han estudiado suficientemente las relaciones entre casos de uso, podría ser que haya dos casos que realicen funciones parecidas, quizá de manera contradictoria. Es posible que la descripción de la función de un caso de uso realizada en lenguaje ordinario sea ambigua en cuanto a las combinaciones de condiciones; entonces tal vez sea conveniente escribirla de nuevo en forma de seudocódigo.
4. Especificación de las clases de análisis
Se consideran los tres tipos de clases de análisis que mencionamos a continuación: 1) Las clases de frontera (en inglés, boundary classes) representan en el nivel de análisis la interfaz de usuario por pantalla. Debe haber al menos una para cada papel de cada actor; por lo tanto, cada una representa la interfaz de usuario entre un caso de uso y un actor. Las clases de frontera representan objetos gráficos complejos como ventanas, diálogos por pantalla y menús; en esta etapa no se pretende describir los detalles del formato de estos objetos –y, por lo tanto, normalmente no tendrán atributos– pero pueden tener relaciones de agregación. Ejemplo de agregación entre clases de frontera Una relación de agregación podría ser la que hay entre un formato de pantalla y un botón de la misma, cuando se pone en marcha un proceso.
2) Las clases de entidades corresponden a los objetos del dominio, es decir, los que modelan entidades o acontecimientos del mundo real de los que el software debe utilizar información (que son los atributos de estas clases). Muchos de
© Editorial UOC
148
Ingeniería del software
estos objetos tendrán que ser persistentes, es decir, deben durar más que el proceso que los crea, lo cual obliga a guardarlos en algún fichero o base de datos. 3) Las clases de control corresponden a objetos internos del software y no persistentes. Las operaciones de este tipo de clases contienen la parte principal de los algoritmos de aplicación (sólo quedan fuera de la verificación de la información entrada por la pantalla y la lectura y grabación de los objetos persistentes). Generalmente, no tendrán atributos. En un caso de uso puede haber cualquier número –raramente no habrá ninguna– pero si hay más de una, debe haber una que controle el conjunto del caso de uso. El hecho de distinguir estos tres tipos de clases da más estabilidad a las clases de cada uno de ellos. Así, si se modifica la manera en que se presenta la información al usuario sin cambiar el procesamiento de los datos, sólo hay que modificar clases de frontera. Si se cambian los algoritmos de proceso de los datos sin cambiar la especificación de los datos ni su presentación a los usuarios, sólo será necesario modificar clases de control. Para cada uso, se realiza un diagrama de colaboración donde figuran las clases de los tres tipos y las operaciones que se piden una a la otra. La notación para este tipo de clases es la siguiente:
Esta notación, igual que esta tipificación de las clases, no forma parte del UML.
4.1. Identificación de las clases de entidades
Probablemente, es el paso más difícil y también el que tiene más repercusiones sobre los pasos y etapas posteriores.
© Editorial UOC
149
Capítulo V. Análisis orientado a objetos
La identificación de las clases de entidades consiste en identificar unas primeras clases mediante las cuales se pueda especificar los casos de uso en forma de interacciones. Muchas de estas clases pasarán al diseño y a la implementación, etapas en las que se definirán muchas más clases, cuyo papel será de implementación, y no conceptual. Buscamos clases en el sentido habitual de conjuntos de objetos homogéneos que tienen unos mismos datos (atributos) y comportamiento (operaciones). Además –y a diferencia de cuando se elabora el modelo del negocio– nos interesan las clases de dentro del software y no del entorno. Clases de entornos y de entidades Las clases del entorno pueden ser actores de los casos de uso. En cambio, las clases que sean el modelo de cosas del entorno tratadas por el software sí que son clases de entidades. Regla poco recomendable para determinar las clases fundamentales Una de las reglas utilizadas para determinar cuáles deben ser las clases fundamentales es buscar los sustantivos que haya dentro de la documentación textual de los requisitos y, a continuación, revisar esta lista desde diferentes puntos de vista. Ésta no es una técnica muy aconsejable porque dentro de la documentación textual hay siempre muchos sustantivos que no corresponden a clases, a menudo hay clases importantes que no se designan explícitamente por un sustantivo e incluso puede suceder que los desarrolladores –que no deben tener necesariamente una formación lingüística sólida– tengan dificultades para identificar los sustantivos, sobre todo cuando son idénticos a formas verbales o adjetivos.
He aquí algunas fuentes de clases de entidades: • Una buena fuente de clases, si existen, la constituyen las bibliotecas de clases ya definidas y programadas donde se puedan encontrar clases que tengan relación con los objetivos del software. Una de las ventajas de las bibliotecas de clases es que no sólo conseguiremos identificar clases, sino también reutilizarlas. • Clases sugeridas por los expertos en el dominio. • La documentación (revisada) de los casos de uso, especialmente las descripciones textuales y el glosario: en términos que aparecen a menudo, entidades definidas explícitamente y términos que se dan por conocidos (todos ellos
© Editorial UOC
150
Ingeniería del software
pueden ser, por ejemplo, personas y papeles de personas, objetos físicos, acontecimientos, unidades organizativas –empresas, grupos de estudiantes, equipos, departamentos–, lugares), se eliminan los sinónimos y se adopta la forma singular. Se excluyen inmediatamente los términos que son demasiado vagos o que corresponden a entidades exteriores al sistema, y también en general todo lo que sean acciones o procesos, ya que es más probable que se trate de operaciones (a menos que tengan atributos). Nada impide utilizar las tres fuentes a la vez. Excepto el caso de clases ya implementadas, conviene eliminar las que tengan alguna de estas características: a) Clases sin atributos. Esto indica que el sistema no tiene información para tratar. b) Clases sin operaciones, es decir, que no tienen un papel ni activo ni pasivo en ninguna operación. c) Clases que tienen sólo un atributo; puede ser que realmente no sea una clase, sino un atributo de otra. d) Clases con un sólo objeto. Si se da este caso, es necesario observar si hay otras con atributos y operaciones similares, e intentar unificarlas. También hay que ver si no es preferible considerar los atributos y operaciones de este único objeto como atributos y operaciones de clase.
4.2. Especificación de los atributos de las clases de entidades
Los atributos de las clases de entidades son generalmente datos mencionados de forma explícita en los casos de uso. Esto significa que los usuarios los usan directamente. Puesto que el modelo de análisis conviene que sea independiente del lenguaje de programación, los tipos de los atributos serán tipos abstractos y no tipos soportados por un lenguaje de programación concreto. Asimismo, conviene que se establezca cuáles son estos tipos. Por la misma razón, los nombres de los atributos no deben estar sometidos necesariamente a las restricciones de los nombres
© Editorial UOC
151
Capítulo V. Análisis orientado a objetos
de ningún lenguaje de programación concreto, pero para evitar cambiar los nombres al llegar al diseño, conviene que los nombres de atributo tengan un formato compatible con el de la mayoría de los lenguajes de programación. Formato de los nombres de atributos compatible con la programación Un formato compatible con la programación podría ser, por ejemplo, atributos constituidos sólo por letras, cifras y underscores, sin que éstos puedan figurar ni al principio ni al final. Esto vale para todos los nombres en general: nombres de operaciones, de clases, de parámetros, etc.
4.2.1. Casos especiales en los atributos Ahora veremos una serie de casos especiales en los atributos: 1) Atributos cuyo valor es compartido por diferentes objetos. Serán atributos de clase. 2) Atributos no aplicables a todos los objetos de la clase. Se puede crear una superclase que tenga sólo los atributos que sean aplicables a todos los objetos y después una subclase o más de atributos que sean aplicables a todos los objetos respectivos. 3) Atributos con valores repetitivos. A veces puede ser conveniente definirlos como clase aparte con una asociación n a 1 con la primera, sobre todo si son atributos compuestos o pares de atributos con la misma cardinalidad. 4) Atributos derivados (edad, etc.). Sólo se incluirán si figuran en salidas descritas en los casos de uso, mientras que los que sean simplemente un recurso para reducir la duración de los procesos a cambio de utilizar más espacio en memoria o en la base de datos no se introducirán hasta el diseño, que es cuando se tiene en cuenta este punto de vista.
4.3. Identificación de las relaciones entre clases Llegados a este punto, tenemos una lista en principio completa, aunque provisional, de las clases del software.
© Editorial UOC
152
Ingeniería del software
Clases de entidades y tablas relacionales Las clases de entidades con sus atributos son parecidas a las tablas de una base de datos relacional (ya se ha mencionado antes que muchas de las clases de entidad son persistentes). Pues bien, es como si la tablas estuvieran sin normalizar. De la misma manera que la normalización hace cambiar el contenido de las tablas en términos de atributos y de filas, así como hace definir tablas nuevas, también habrá atributos que pasarán de una clase a otra y se definirán clases nuevas. No obstante, asimismo, conviene tener claros los límites de esta analogía: ni hay correspondencia clara entre los pasos de la normalización de tablas relacionales y los de la revisión de la lista de clases, ni ésta se encuentra tan formalizada como aquélla, por ahora.
Se examinarán las relaciones de herencia, las asociaciones y las relaciones de agregación. A pesar de que hablaremos sobre esto en este orden, es un proceso iterativo en el cual puede suceder, por ejemplo, que la identificación de una asociación haga cambiar una jerarquía de herencia.
4.3.1. Jerarquías de herencia Es necesario establecer las jerarquías de herencia, tarea que se realiza por medio de dos vías, la generalización y la especificación. Especificación
En lo que respecta a la especificación, hay que tener en cuenta lo siguiente: 1) Sólo hay que añadir una subclase si sus atributos tendrán atributos, operaciones o asociaciones que no tendrá el resto de los objetos de la superclase. Es preciso evitar sistemáticamente subclases correspondientes a los diferentes estados que pueden tener los objetos de la superclase. Sólo debe definirse una subclase para un estado si se da alguna de las circunstancias mencionadas. Como el join de dos tablas en una base de datos relacional. 2) Si se puede, hay que evitar la doble especificación, es decir, que de una superclase se distingan dos conjuntos independientes de subclases. A veces, esto puede ser consecuencia del hecho de que la superclase sea en realidad la combinación de dos clases.
© Editorial UOC
153
Capítulo V. Análisis orientado a objetos
Ejemplo de combinación de dos clases Consideremos el ejemplo siguiente, adaptado de uno de Richter: si las cuentas de un banco se dividen, desde un punto de vista, en cuentas corrientes y cuentas a plazo, y, desde otro, en cuentas de personas y cuentas de empresas, sería mejor distinguir dos clases diferentes –cuentas y clientes– unidas por una asociación y con dos subclases en cada una, cuentas corrientes y cuentas a plazo, en cuentas, y personas y empresas, en clientes.
Generalización
En cuanto a la generalización, hay que tener en cuenta estos puntos: 1) Si diferentes clases de significado parecido tienen atributos u operaciones en común, hay que considerar la posibilidad de definir una superclase común a todas estas clases que agrupe todos los atributos y operaciones en cuestión. Para que los atributos comunes puedan ponerse dentro de la superclase, es necesario que estén definidos igual en todas las clases, pero las operaciones sólo deben tener la misma signatura (o, por lo menos, el mismo nombre) y una función análoga a todas las clases, ya que las operaciones de la superclase pueden ser abstractas. La superclase será abstracta, ya que todos sus objetos pertenecerán a alguna de las clases iniciales (a menos que al definir la superclase nos demos cuenta de que hay objetos de ésta que no son de ninguna de estas clases y que, por lo tanto, faltaban clases por identificar). Ahora bien, que la superclase sea abstracta no significa que deban serlo todas sus operaciones –las operaciones que se realicen de la misma manera en todas las subclases serán operaciones concretas de la superclase. 2) Conviene situar todos los atributos y operaciones comunes lo más arriba posible dentro de la jerarquía de herencia, aunque las operaciones deban ser abstractas. 3) Habiendo definido una superclase, puede ocurrir que una subclase tenga todos sus atributos y operaciones heredados, es decir, que no tenga ninguno propio; entonces se puede suprimir esta subclase, y la superclase será evidentemente concreta. 4) No tiene sentido que una superclase abstracta tenga sólo una subclase (y tampoco se prevean más en el futuro). Será necesario suprimir la superclase. En
© Editorial UOC
154
Ingeniería del software
cambio, puede ser normal que suceda lo mismo con una superclase concreta, por ejemplo, como resultado de la situación del punto anterior. 5) Una superclase abstracta puede heredar tanto operaciones concretas como operaciones abstractas, y sus operaciones propias pueden ser tanto abstractas como concretas. 6) ¿Qué se puede hacer si hay tres subclases, y un atributo u operación es común sólo a dos de éstas? Una solución es añadir un nivel intermedio en la jerarquía de herencia, de manera que las dos clases en cuestión sean subclases de una que tenga el atributo u operación mencionado. No obstante, si también existiera un atributo u operación que fuera común a las subclases primera y tercera, sería necesaria una nueva subclase intermedia, y entonces la primera subclase lo sería de las dos subclases intermedias, ya que tiene ambas operaciones, y por lo tanto estaríamos en un caso de herencia múltiple. En el caso de una operación, existe la opción adicional de incluirla dentro de la superclase de las tres subclases y redefinirla como una operación nula dentro de la tercera subclase (esto sólo sería viable si la superclase fuera abstracta, ya que si fuera instanciable y se crease un objeto de ésta que también fuera de la tercera subclase, le sería aplicable la operación tal como se habría definido en la superclase). Hablando de la agregación veremos otra solución a este problema.
4.3.2. Herencia múltiple
La herencia múltiple consiste en el hecho de que una clase tiene diferentes superclases y, por lo tanto, hereda atributos, operaciones, asociaciones y agregaciones de todas éstas. Existe conflicto si la superclase hereda dos atributos, operaciones o asociaciones con el mismo nombre y diferentes propiedades (herencia repetida), ya que en principio no se sabe cuál prevalece, y hay que establecer un criterio, poco o muy arbitrario, para decidirlo. Algunos lenguajes de programación no soportan la herencia múltiple, y entonces en la etapa de diseño hay que adaptar el diagrama estático, pero no por esta razón se debe renunciar a utilizar la herencia múltiple en el análisis si procede.
© Editorial UOC
155
Capítulo V. Análisis orientado a objetos
4.3.3. Interfaces
Recordad que las interfaces del UML equivalen a clases abstractas sin atributos y con todas las operaciones abstractas. En el lugar de las subclases, definidas estáticamente, están las clases que implementan la interfaz, que se pueden sustituir sin modificarla. Esto hace que las interfaces sean una alternativa a las clases abstractas que puede ser ventajosa desde el punto de vista de la flexibilidad.
4.3.4. Asociaciones Hay una asociación entre clases cuando los objetos de una necesitan la colaboración de objetos de otra para llevar a cabo sus operaciones. Por esta razón, es obvio que hay asociaciones entre las clases de frontera y al menos algunas clases de control, por un lado, y entre clases de entidades, por otro. Las clases de control que no estén asociadas a clases de frontera estarán asociadas a otras clases de control. En relación con las asociaciones conviene tener en cuenta lo siguiente: 1) Tanto las asociaciones como los papeles que hacen las clases en las mismas pueden tener nombres. Muchas veces no es necesario dar a la vez nombres a la asociación y a todos sus papeles, puesto que uno u otro sería banal, pero si la asociación no tiene nombre, debe tenerlo al menos uno de sus papeles. 2) Entre dos clases (o más) puede haber más de una asociación, con significado diferente (y entonces puede ser que estas asociaciones enlacen todas ellas los mismos objetos concretos o no). Es necesario que sean diferentes los nombres de estas asociaciones o los nombres de sus papeles.
Asociaciones diferentes: entre dos clases Consideremos el ejemplo siguiente, adaptado de Richter: en una clase de vuelos comerciales, hay la compañía, el número de vuelo, el aeropuerto de origen y el de destino, el día y la hora de salida, y todos los vuelos con el mismo número tienen la misma compañía y los mismos aeropuertos de origen y de destino. Una opción me-
© Editorial UOC
156
Ingeniería del software
jor, que evitaría estas repeticiones, sería sustituir la clase por dos: una que tuviera el número de vuelo, la compañía y los aeropuertos de origen y de destino y otra que tuviera la fecha y hora de salida, con una asociación de una a varias entre las dos (esto es análogo al paso de la segunda a la tercera forma normalizada en bases de datos relacionales).
3) Si existen asociaciones entre la clase A y cada una de las subclases de la clase B, es mejor sustituirlas por una única asociación entre A y B; no sólo el diagrama es más sencillo, sino que, si se añade una nueva subclase, no es necesario añadir una nueva asociación. 4) Puede haber una asociación (binaria o no) entre una clase y ella misma. Ejemplo de asociación entre una clase y ella misma Todos los empleados de una empresa (menos uno) tienen un jefe que es también empleado. Ahora bien, un empleado no puede ser jefe de sí mismo, y en general un objeto no puede estar asociado a sí mismo, ya que esta situación podría producir un bucle sin fin.
5) Conviene una clase asociativa cuando se da una de estas circunstancias: la asociación tiene atributos o bien hay una clase cuya vida de los objetos está relacionada con la de los enlaces de la asociación y sólo tiene un objeto para cada enlace. 6) Conviene revisar cada asociación con cardinalidad múltiple en los dos papeles para determinar si no debería ser una clase asociativa. Es decir, las asociaciones m : n.
4.3.5. Agregaciones
Las agregaciones se pueden considerar un caso particular de las asociaciones, en el cual el significado de la asociación es que un papel es parte del otro en algún sentido, y ciertamente conviene aplicarlo, en general, siempre que nos encontremos en casos de este tipo. La agregación, no obstante, tiene algunas propiedades que la pueden hacer útil también para situaciones en las que puede sustituir a otras relaciones, principalmente de herencia, con vistas al hecho de que el software desarrollado sea más flexible:
© Editorial UOC
157
Capítulo V. Análisis orientado a objetos
• La clase compuesta delega en las clases componentes las operaciones y atributos que hacen referencia a ellas. Esto no es imprescindible, pero es muy recomendable en general. • Los componentes se pueden crear y borrar en tiempo de ejecución, mientras que las subclases deben definirse en tiempo de compilación. • Los componentes –sobre todo si la agregación es composición– no es necesario que sean visibles desde el exterior, lo cual significa que se puede cambiar la estructura de los objetos de una clase compuesta sin afectar a otras clases. • Entre dos clases puede haber varias relaciones de agregación (que entonces deberán distinguirse por el nombre), de la misma manera que puede haber distintas asociaciones. Algunas aplicaciones no obvias del concepto de agregación son éstas: 1) Para utilizar la agregación como alternativa a las subclases, es necesario hacer lo siguiente: los atributos y operaciones que serían específicos de la subclase se ponen en una nueva clase que se define como componente de la anterior con una cardinalidad mínima de cero, de manera que los objetos de la clase inicial que deben tener los atributos y operaciones en cuestión tendrán este componente y los demás no lo tendrán. Para cambiar de subclase un objeto, sería necesario borrarlo y crearlo otra vez, ahora en la subclase nueva, con lo cual las eventuales referencias a éste dejarían de ser válidas; con la agregación, simplemente sería necesario borrar del objeto el componente correspondiente a la subclase antigua y añadirle el de la nueva. 2) Puesto que el valor máximo de la cardinalidad de un componente puede ser mayor que 1, el caso de los atributos con valores repetitivos descrito en otro subapartado puede ser resuelto con agregación (en principio, composición) en lugar de asociación. 3) El hecho de que en una agregación o composición los componentes pueden ser compartidos sugiere una alternativa a la herencia múltiple, que además soluciona la herencia repetida, ya que no habrá dos atributos u operaciones con el mismo nombre, sino sólo uno. 4) El caso de los atributos u operaciones compartidos por dos subclases de tres mencionado en otro subapartado se puede resolver poniendo todos los atributos y operaciones no comunes a dos subclases en una nueva clase que sería componente compartido de ambas.
© Editorial UOC
158
Ingeniería del software
5) La herencia múltiple también se puede resolver al revés de como se ha hecho antes: haciendo que la subclase sea la clase compuesta y las superclases, sus clases componentes. Esta solución permite añadir superclases sin que sea necesario modificar la subclase.
4.4. Identificación de las clases de frontera, las clases de control y de las operaciones. Diagrama estático de análisis De la descripción textual de los casos de uso salen las operaciones de las clases de frontera y también, de manera más indirecta, las de las clases de control; las de las clases de entidades muchas veces están implícitas, pero casi siempre son obvias. Operaciones 1) Las operaciones de las clases de frontera son: introducir y presentar datos. 2) Las operaciones de las clases de entidades son: añadir, borrar, leer, regrabar o equivalentes.
Una manera sistemática de buscar y documentar las clases de frontera, de control y las operaciones de los tres tipos de clases es elaborar diagramas de colaboración simplificados de los casos de uso representando las tres clases de los tres tipos. Después, conviene realizar un diagrama estático en el que figuren todas las clases de los tres tipos, con los atributos y operaciones identificadas y con todas las relaciones entre ellas, que es el diagrama estático de análisis.
5. Especificación formal de los casos de uso
Cuando llegamos a este punto, tenemos descrito de manera formal –mediante el diagrama estático de análisis– lo que podríamos denominar la estructura estática del software que se desarrolla. Queda representar de manera formalizada el comportamiento del sistema, y el modo más natural de hacerlo es describiendo formalmente los casos de uso.
© Editorial UOC
159
Capítulo V. Análisis orientado a objetos
En el paso de especificación de las clases de análisis se han elaborado unos diagramas de colaboración simplificados de los casos de uso, cuya finalidad no era describir de manera formal y detallada el proceso de cada uno, sino identificar las clases de frontera y de control y las operaciones de éstas y de las clases de entidades. La forma simplificada que se ha utilizado no tiene en cuenta la secuencia de los mensajes ni el hecho de que puedan ser repetidos un cierto número de veces o sujetos a condiciones. Esta especificación puede ser suficiente para algunos casos de uso sencillos, pero otros necesitarán una especificación complementaria; para éstos, será necesario realizar diagramas de secuencia o de colaboración completos, o, a veces, diagramas de actividades. También se pueden hacer diagramas de estados para ilustrar, más que casos de uso en particular, el comportamiento de algunas clases de entidades o de control. En el caso de las primeras, el diagrama de estados seguramente repetirá desde otro punto de vista lo que ya se haya especificado en los casos de uso afectados, mientras que en el caso de clases de control, puede formar parte de la descripción de su comportamiento.
6. Análisis de la interfaz de usuario
El análisis de la interfaz de usuario parte de la información siguiente: • la documentación de las tareas futuras, • las especificaciones de usabilidad, • la lista de las clases frontera, y tiene como objetivo un esquema del contenido de cada ventana asociada a una clase de frontera, excepto las denominadas ventanas secundarias, que sólo sirven para aspectos como presentar mensajes al usuario o pedirle confirmaciones o la introducción del valor de un parámetro. Es muy importante comentar con los usuarios el contenido de las ventanas y la interacción entre el actor y el sistema.
© Editorial UOC
160
Ingeniería del software
7. Ejemplo Ya hemos visto un ejemplo de recogida y documentación de requisitos. Ahora continuaremos el proceso realizando el análisis para el mismo caso.
7.1. Revisión de los casos de uso
Consultad la documentación textual en el subapartado 6.6.3 del capítulo “Recogida y documentación de requisitos” de esta obra. Los casos de uso obtenidos en la etapa anterior son sencillos y parece que tal como son ya se pueden utilizar como base para los pasos posteriores. Ahora bien, en la documentación textual, en el apartado de “Otros requisitos”, se indica que debe ser posible consultar, modificar y borrar toda la información. Para cumplir con este requisito, sería necesario añadir algunos casos de uso, triviales en general; no se ha hecho, porque no aportarían ningún concepto nuevo importante y alargarían mucho el ejemplo. En cualquier caso, conviene tener presente que en sistemas de software reales la información debe poderse modificar (para corregirla, por lo menos), que toda la información se debe poder consultar –a menudo de diferentes maneras– y que raramente hay información eterna; hay que borrar la que ya no sea necesaria (a veces, puede ocurrir que, en lugar de borrar totalmente la información que ya no se utiliza, se copie en un fichero histórico, normalmente en soportes no permanentemente on-line como disquetes y cintas magnéticas).
7.2. Paquetes de análisis y de servicios Evidentemente, en la realidad, en un caso tan sencillo como éste sólo habría un paquete. Sin embargo, si atendemos al grado de dependencia entre los casos de uso, podríamos distinguir dos paquetes de análisis: Locales, que comprende los casos de uso relativos a los locales y propietarios (los casos de uso 1, 2 y 3), y los referentes a contratos y alquileres (el resto); dentro del primero podríamos distinguir dos paquetes de servicios: BasicoLocales e Informes si consideramos
© Editorial UOC
161
Capítulo V. Análisis orientado a objetos
opcional la introducción del informe del inspector, y Alquileres, dentro del cual se podría considerar que los casos de uso 6 y 7 son opcionales y constituyen un paquete de servicio Consultas separado de Contratos, que comprende los casos de uso 4 y 5. El esquema de las relaciones entre los paquetes sería el siguiente:
Las flechas como las del diagrama indican relaciones de dependencia.
7.3. Identificación de las clases de entidades
Empezaremos por identificar las clases de entidades a partir de los casos de uso. Para cada caso de uso se indican las clases que se encuentran; cuando una clase ya se había identificado en un caso de uso anterior, su nombre va seguido de un asterisco, mientras que las clases que son dudosas van seguidas de un interrogante. • Caso de uso número 1: ‘Añadir local’. Clases: Local, Propietario, Zona? • Caso de uso número 2: ‘Añadir propietario’. Clases: Propietario*, Particular? Empresa?
© Editorial UOC
162
Ingeniería del software
• Caso de uso número 3: ‘Introducir informe’. Clases: Local*, Instalación? Inspector? • Caso de uso número 4: ‘Introducir contrato’. Clases: Local*, Arrendatario, Contrato, Vendedor? • Caso de uso número 5: ‘Añadir alquiler’. Clases: Alquiler*. • Caso de uso número 6: ‘Añadir arrendatario eventual”. Clases: Arrendatario eventual. • Caso de uso número 7: ‘Buscar locales’. Clases: Local*. Comentarios
Las clases Zona e Instalación se descartan porque no tienen ningún atributo y, por lo tanto, se pueden considerar atributos de otras clases. Inspector y Vendedor, que no se mencionan en la descripción de los casos de uso, pero sí en las cuestiones que hay que aclarar y sus propuestas, están en el mismo caso. Particular y Empresa se descartan como clases (serían subclases de Propietario y de Arrendatario) porque no tienen ni atributos ni operaciones propias. Por lo tanto, la primera lista de clases de entidades es ésta: Local, Propietario, Arrendatario y Arrendatario eventual.
7.4. Especificación de los atributos de las clases de entidades En la lista que vemos a continuación, presentamos los atributos de las clases de entidades correspondientes al ejemplo que consideramos. • Clase Local: zona(string), tipo(string), numero(integer), direccion(text), superficie(real), caracteristicas(text), volumen(real), caracteristicas_polivalente(text), NIF_propietario(string), accesibilidad(text), instalaciones(text), agente(string), inspector(string). Clase El atributo nombre del Propietario, Arrendatario y Arrendatario eventual contiene los apellidos y nombre o bien la razón social según si el propietario es una persona física o una empresa.* *. Conviene que los nombres de los atributos respeten el formato soportado por los compiladores; por lo tanto, es mejor no poner acentos ni caracteres especiales.
© Editorial UOC
163
Capítulo V. Análisis orientado a objetos
• Clase Propietario: NIF(string), nombre(text), direccion(text), telefono(string). • Clase Arrendatario: NIF(string), nombre(text), direccion(text), telefono(string). • Clase Arrendatario eventual: NIF(string), nombre(text), direccion(text), telefono(string), tipo_local(string), zona(string), superficie_minima(real), varios(text). • Clase Contrato: NIF_arrendatario(string), NIF_propietario(string), vendedor(string).
7.5. Relaciones
7.5.1. Relaciones de herencia
Puesto que las tiendas-almacén tienen un atributo propio, el volumen, se define TiendaAlmacen como subclase de Local. Debido a que los polivalentes tienen también un atributo propio, las caracteristicas_polivalente, se define la subclase Polivalente de TiendaAlmacen; puesto que los polivalentes son también oficinas, igualmente deben ser subclase y, por lo tanto, hay que definir Oficina como subclase de Local. La subclase Inmueble se añade por claridad del diagrama, ya que todos los locales que no son tiendas-almacén ni oficinas son inmuebles; por esta razón, Local es una clase abstracta. Por claridad, el hecho de que una clase es abstracta se indica de dos maneras: con el nombre en cursiva y con la propiedad abstract. Recordad, sin embargo, que con una sola es suficiente.
Los atributos comunes a Propietario y Arrendatario se ponen dentro de una superclase abstracta, Cliente; ArrendatarioEventual es subclase de Arrendatario a consecuencia de los atributos. Puesto que resulta que Propietario y Arrendatario no tienen más atributos que los heredados, podríamos pensar en suprimirlas, pero no se hace porque tienen comportamiento diferente: Propietario tiene apartamentos y Arrendatario los alquila.
© Editorial UOC
164
Ingeniería del software
© Editorial UOC
165
Capítulo V. Análisis orientado a objetos
7.5.2. Asociaciones
En este diagrama podéis ver las asociaciones del ejemplo:
La asociación entre Propietario y Local se deduce del caso de uso 1: ‘Añadir local’, y la clase asociativa Contrato se deduce del caso de uso 4: ‘Introducir contrato’. Fijaos en que la asociación Contrato se establece con la superclase Local y no con sus subclases, ya que es común a todas. En cambio, las relaciones se establecen con las subclases Propietario y Arrendatario por la razón contraria. Observad también que se han podido suprimir los atributos NIF_propietario y NIF_arrendatario de las clases Contrato y Local, porque son redundantes con las asociaciones. Implementación de las asociaciones Podría suceder que a la hora de programar las asociaciones se implementasen precisamente mediante atributos como los que se acaban de ver (más una lista de los códigos de los locales de cada propietario), y entonces sería necesario volver a añadirlos; pero también se podrían implementar las asociaciones de otras maneras.
© Editorial UOC
166
Ingeniería del software
7.5.3. Agregaciones
Según los requisitos, un inmueble se compone de tiendas-almacén y/o oficinas; por lo tanto, entre estas tres subclases hay las agregaciones correspondientes. Estas agregaciones son composiciones, puesto que cada tienda-almacén u oficina pertenece a un solo inmueble.
7.6. Identificación de las clases de frontera, las clases de control y de las operaciones
Para cada caso de uso, realizaremos un diagrama de colaboración simplificado. En todos los casos de uso se ha puesto que el actor pide una opción a la clase de frontera Menu, que corresponde al menú de la aplicación, y ésta la pasa a la clase de control GestorMenu, que llama a la clase de control principal del caso de uso. Los nombres de los mensajes serán operaciones de las clases destinatarias: los que van de las clases de frontera al actor no le piden ninguna operación, como es lógico. Caso de uso 1: ‘Añadir local’
Este caso de uso comprende el caso de uso 2: ‘Añadir propietario’, el cual, como sabemos, lo extiende cuando no se ha encontrado al propietario.
© Editorial UOC
167
Capítulo V. Análisis orientado a objetos
Caso de uso 2: ‘Añadir propietario’
Caso de uso 3: ‘Introducir informe’
Como se puede ver en el diagrama de colaboración de este caso de uso:
Se busca el local y, si no se encuentra, se envía un mensaje de error al actor. Si se ha encontrado, una vez introducidos los datos del informe se modifica el objeto Local dando valores a los campos correspondientes y grabándolo de nuevo en la base de datos. Caso de uso 4: ‘Introducir contrato’
Como podéis observar en el diagrama, si no se encuentra al arrendatario, se crea (caso de uso 5: “Añadir arrendatario”), pero, si no se encuentra el local, se en-
© Editorial UOC
168
Ingeniería del software
vía un mensaje de error al actor. La clase ImpresionContrato imprime los datos del contrato.
Casos de uso 5 y 6: ‘Añadir arrendatario’ y ‘Añadir arrendatario eventual’
Sabemos que el caso de uso 6 es una especialización del caso de uso 5, ya que difiere de éste en que se añaden los valores de los atributos que indican qué tipo de locales quiere el arrendatario eventual, que están en la subclase ArrendatarioEventual. Por lo tanto, los podemos convertir en un único caso de uso que crea o bien un objeto de Arrendatario o bien un ArrendatarioEventual, respectivamente.
© Editorial UOC
169
Capítulo V. Análisis orientado a objetos
Caso de uso 7: ‘Buscar locales’
Como podéis ver en el diagrama de colaboración:
El actor da los argumentos de la consulta. Le sale una lista de los códigos de los locales que cumplen las condiciones, dentro de la cual el actor puede elegir un local de la lista, y se le presentan allí los datos del mismo (todos o bien todos excepto la dirección del local y el NIF del propietario).
7.7. Especificación formal de los casos de uso
Seguramente habréis observado que en algunos de los diagramas de colaboración simplificados que acabamos de ver hay mensajes que sólo se envían cuando se cumple una condición, y que también, a veces, entran y salen diferentes mensajes de una misma clase sin que quede claro en qué orden lo hacen. Por lo tanto, será necesario realizar una especificación más detallada de estos casos de uso. Puesto que ya hemos realizado un diagrama de colaboración –aunque sea simplificado–, ahora utilizaremos el diagrama de secuencias, porque da una visión de los casos de uso que es complementaria de la que ya tenemos; sólo se hará para un caso de uso, el más complicado, el caso de uso 4: ‘Introducir contrato’. También veremos el diagrama de estados de la única clase en que no es trivial, la clase Local.
© Editorial UOC
170
Ingeniería del software
a) Diagrama de secuencias del caso de uso 4: ‘Introducir contrato’:
b) Diagrama de estados de la clase Local:
© Editorial UOC
171
Capítulo V. Análisis orientado a objetos
7.8. Análisis de la interfaz de usuario Veamos el esquema de ventana correspondiente a cada clase de frontera. 1) Clase PantallaAñadirLocal.
2) Clase PantallaAñadirPropietario
© Editorial UOC
3) Clase PantallaIntroducirInforme.
4) Clase PantallaIntroducirContrato
172
Ingeniería del software
© Editorial UOC
173
Capítulo V. Análisis orientado a objetos
5) Clase PantallaAñadirArrendatario
6) Clase PantallaBuscarLocales
En la cabecera… … salen los valores de los argumentos de la búsqueda dados por el usuario y, debajo, la lista de los códigos de los locales que cumplen las condiciones correspondientes. “Información completa?” sirve para indicar si el usuario quiere que aparezcan también la dirección del local y el NIF del propietario. “Selección” sirve para pedir los datos de un local concreto.
© Editorial UOC
174
Ingeniería del software
7) Clase PantallaListaLocales
8) Clase PantallaDatosLocal El esquema de la ventana es el mismo que para la clase PantallaIntroducirInforme más una opción para imprimir su contenido.
© Editorial UOC
175
Capítulo V. Análisis orientado a objetos
Conclusiones
Hemos visto cómo se lleva a cabo la etapa de análisis según un método basado en el Rational Unified Process. El objetivo de esta etapa es modelar los requisitos de una manera adecuada para servir de base del desarrollo propiamente dicho del software. Se empieza por revisar los casos de uso especificados en la etapa anterior con el objetivo de eliminar redundancias y añadir eventuales casos de uso no pedidos explícitamente por los usuarios, pero que, sin embargo, son necesarios para satisfacer los requisitos. Después se identifican las clases de entidades, sus atributos y las relaciones entre ellas, y a continuación se realiza un diagrama de colaboración simplificado para cada caso de uso con el objetivo de identificar las clases de frontera, de control y las operaciones de éstas y de las clases de entidades. De este modo se acaba de obtener la información necesaria para elaborar el diagrama estático de análisis. Después se realizan diagramas de interacción más detallados para los casos de uso que sean necesarios, y eventualmente se hacen también diagramas de actividades, de estados y transiciones. El análisis de la interfaz de usuario consiste en describir el contenido de las ventanas asociadas a las clases frontera, partiendo de la lista de las mismas y de la descripción de las tareas futuras. Así se ha obtenido lo que hemos denominado modelo de análisis.
© Editorial UOC
177
Capítulo VI. Diseño orientado a objetos
Capítulo VI
Diseño orientado a objetos
Este capítulo trata del diseño del software con técnicas orientadas a objetos, aplicando las notaciones y conceptos del UML y siguiendo el ciclo de vida del Rational Unified Process. Recordemos que, en este ciclo de vida, el análisis y el diseño constituyen un único componente de proceso, pero nosotros los consideraremos dos etapas diferentes porque tienen una finalidad distinta y porque los resultados de uno y otro son también claramente diferentes. Se verá con detalle el papel del diseño en relación con la etapa que le precede, el análisis, y la que le sigue, la realización. Avanzamos, sin embargo, que así como el análisis formaliza los requisitos recogidos anteriormente, el diseño es el primer paso de la elaboración de una respuesta a estos requisitos. Una de las ventajas esperadas de la tecnología orientada a objetos, y quizá la más importante, es la posibilidad de reutilizar software. Durante el diseño se decide qué se reutiliza y qué se hace de nuevo y, por tanto, en este módulo tenemos que tratar las técnicas de reutilización. Dentro del diseño, distinguiremos los pasos siguientes:
• El diseño arquitectónico. • El diseño de los casos de uso. • La obtención del diagrama estático de diseño. • La especificación de las clases del diseño. • El diseño de la persistencia. • El diseño de la interfaz de usuario. • El diseño de los subsistemas.
© Editorial UOC
178
Ingeniería del software
1. El papel del diseño
La etapa de diseño hace de puente entre el análisis y la realización. El modelo del análisis describe las funciones que tiene que desempeñar el software y también especifica los eventuales requisitos no funcionales, es decir, plantea el problema que se debe resolver con el software. Las etapas siguientes tendrán que ver con la elaboración de una solución a este problema. Ahora bien, el modelo del análisis no es una base adecuada para emprender directamente la realización, ya que no se expresa en términos de la tecnología que deberá utilizar en el proyecto (principalmente el lenguaje de programación y la herramienta de apoyo a la interfaz gráfica de usuario). Justificación de la etapa de diseño Está claro que, al especificar los requisitos, se habrán tenido en cuenta las posibilidades generales de la tecnología disponible, con el fin de no pedir requisitos imposibles, ni tampoco infrautilizar esta tecnología en el caso de que permitiera atender más necesidades del usuario o atenderlas mejor (por ejemplo, hoy día el análisis considera implícitamente que la presentación de la información a los usuarios se hará mediante pantallas con apoyo de gráficos e impresoras modernas). No obstante, seguramente no se habrá tenido en cuenta, si no es de una manera muy general, en qué lenguaje de programación se implementarán las clases y qué clases programadas en proyectos anteriores se reutilizarán, o qué sistema de gestión de bases de datos se usará.
Dentro del Rational Unified Process, el diseño se hace principalmente al final de la fase de elaboración y al comienzo de la de construcción.
1.1. La relación entre el diseño y la realización La realización da como producto el software acabado, y comprende la programación propiamente dicha más la generación de ficheros binarios y ejecutables, la prueba uno a uno de los mismos y el enlace de todo. Las clases definidas en el diseño se programan una a una, y se generan los componentes y los subsistemas. Entre el modelo del diseño y el software acabado existe la misma relación que entre el proyecto de un edificio y el edificio construido.
© Editorial UOC
179
Capítulo VI. Diseño orientado a objetos
1.2. La utilidad del diseño Hemos visto que en proyectos muy sencillos se puede llegar a prescindir del análisis. En cambio, el diseño es siempre necesario. Preguntar para qué sirve el diseño es lo mismo que preguntar por qué no se puede implementar directamente el modelo de análisis. Jacobson, Booch y Rumbaugh mencionan una relación de 1 a 5 entre el coste del análisis y el del diseño. Este hecho ya indica que en el modelo del diseño hay muchas más clases y operaciones que se deben identificar y especificar antes de programarlas.
2. La reutilización La reutilización en el diseño orientado a objetos tiene cuatro modalidades: la reutilización de clases, la reutilización de componentes, los patrones y los marcos. Meyer menciona las siguientes ventajas de la reutilización: • Se abrevia el desarrollo del software. • Disminuye el trabajo de mantenimiento del software en el futuro. • Mejora la fiabilidad. • A menudo el código reutilizado es más eficiente, probablemente porque se ha ido mejorando con el tiempo. Es cierto que el código hecho a medida para un caso concreto podría ser más eficiente, pero en la práctica no es posible optimizar todo el código de un proyecto. • Se gana en coherencia. Normalmente no se reutiliza una sola clase, sino varias, procedentes de una misma librería y que, por tanto, seguramente estarán programadas según las mismas normas y con el mismo estilo. • Preservación de la inversión. Si se reutiliza un buen fragmento de código, será mucho más difícil que se pierda, ya que habrá muchas copias.
2.1. La reutilización de clases Principalmente, se reutilizan clases que tienen funciones independientes del dominio, como elementos de interfaz gráfica y estructuras de datos generales.
© Editorial UOC
180
Ingeniería del software
Por lo común, la reutilización de clases de un dominio concreto sólo es viable en el caso de sistemas de software de una misma organización. Las clases que se reutilizan se suelen agrupar por función en librerías como los paquetes de Java. La reutilización de clases se puede hacer de varias maneras. La más sencilla y directa es reutilizar la clase misma, en forma fuente o compilada. No obstante, si se le tienen que añadir o modificar operaciones o atributos, hay que complementarla con subclases o mediante agregación. Si la clase es abstracta, la única manera de reutilizarla es, evidentemente, con subclases.
2.2. La reutilización de componentes
Un componente es un conjunto de clases, cuyos objetos colaboran en tiempo de ejecución con el fin de llevar a cabo una función concreta. Un componente implementa una interfaz determinada, que es el conjunto de todas las operaciones de sus clases que se pueden pedir desde el exterior del componente. Por tanto, se puede sustituir un componente por otro que implemente la misma interfaz. Un componente, por el hecho de que implementa una interfaz, se comporta como una clase, y las clases que lo componen no son visibles desde el exterior. Para que un componente se pueda reutilizar correctamente, se debe conocer su interfaz y también el contrato. El contrato describe los efectos de las operaciones comprendidas en la interfaz y qué invariantes mantiene.
2.3. Los patrones
Los patrones (en inglés, patterns) son una manera organizada de recoger la experiencia de los diseñadores de software para volverla a utilizar en casos parecidos. Cuando un experto trabaja en un problema, raramente inventa una solución del todo nueva, partiendo de cero, sino que en general recuerda algún caso que tiene semejanzas con el suyo y adapta la solución. Esto es lo que acostumbramos a denominar aplicar la experiencia, y se supone que es lo que hace que los expertos lo sean.
© Editorial UOC
181
Capítulo VI. Diseño orientado a objetos
No es necesario decir que sería mucho mejor tener esta experiencia recogida y documentada de manera más o menos formal para hacerla accesible a otros expertos o futuros expertos, por un lado, y para hacer más sistemática y coherente la aplicación de la experiencia por los mismos expertos, por el otro. Un patrón no es un programa, aunque puede incluir un programa como muestra, pero no para utilizarlo directamente. Un patrón es una idea de diseño e implementación detallada y práctica (una “receta”) que constituye un esbozo de solución de un problema que se presenta con una cierta frecuencia. Los detalles de esta solución cambian para cada caso al que se aplica. Por tanto, el núcleo de un patrón es una pareja problema-solución. En general, un patrón no está vinculado a un método concreto de diseño. De hecho, muchos patrones se pueden utilizar tanto en diseño orientado a objetos como en diseño estructurado, si bien los patrones tienden a estar documentados en forma orientada a objetos, simplemente porque se han divulgado cuando esta tecnología ya estaba en boga. Los patrones representan un nuevo intento de aumentar la reusabilidad del software (como la tecnología de objetos, por ejemplo) partiendo de la idea de que en casos determinados en los que no se puede reutilizar código, al menos se puede reutilizar el diseño, como mínimo las ideas básicas. De igual manera que los entornos de desarrollo orientados a objetos acostumbran a ofrecer una amplia biblioteca de clases predefinidas, en el diseño orientado a patrones se puede disponer de “recetarios” de patrones preexistentes, que hay que esperar a que se vayan enriqueciendo con el paso del tiempo. Además, también hay que esperar a que vayan apareciendo (ya han comenzado a hacerlo) específicos por dominios. Como programación en tiempo real, programación distribuida y muchos otros. El principal beneficio que se espera obtener de la utilización de patrones es que no hay que pensar una solución para muchos de los problemas de diseño más frecuentes y, por tanto, se puede concentrar el esfuerzo de diseño en los aspectos más innovadores de cada proyecto. Patrones y derechos de propiedad Sin duda se plantearán, si todavía no se han presentado, cuestiones como patentes y propiedad intelectual sobre patrones, patrones que sean secreto de empresa, etc.
© Editorial UOC
182
Ingeniería del software
2.3.1. Características de los patrones
Las características más importantes que presentan los patrones son las que mencionamos continuación: 1) Recogen la experiencia, es decir, son un extracto y un denominador común de numerosos diseños anteriores: no se inventan en un momento dado. 2) Son algo más amplio que, por ejemplo, una clase o un objeto. 3) Crean vocabulario. Dentro de un diseño se hace referencia a los patrones por su nombre. En particular, dentro de un patrón se puede hacer referencia a otros. 4) Son un instrumento de documentación, dado que dentro de la documentación del diseño, una referencia a un patrón ahorra describir con detalle una parte del diseño. 5) Si se utiliza el mismo patrón, facilitan la coherencia de los diseños por todas las partes donde se presenta el mismo problema. 6) No dan una solución completa a un problema en un caso concreto: sólo proporcionan una solución genérica que hay que completar. 7) Ayudan a hacer frente a la complejidad del diseño, resolviendo de entrada algunas partes.
2.3.2. Componentes de los patrones
Un patrón tiene las cuatro partes que mencionamos a continuación: 1) El nombre. La asignación de nombre a un patrón no es una cuestión trivial, ya que, por el hecho de que crean vocabulario, es vital que en los nombres de los patrones no haya sinónimos o alias, ni menos aún homónimos; y esto, no sólo en lo que respecta al proyecto o empresa, sino también en cuanto a la literatura sobre patrones en general, dado que cualquier experto que mire el diseño tiene que dar la misma interpretación. 2) El contexto. Es el entorno o la situación dentro de la cual se presenta el problema que el patrón resuelve. A menudo se define en términos de una lista de situaciones.
© Editorial UOC
183
Capítulo VI. Diseño orientado a objetos
3) El problema. Se define en términos de lo que se conoce como fuerzas: requisitos que la solución tiene que cumplir, restricciones y cualidades que se desea que tenga la solución. A veces, las fuerzas están contrapuestas. 4) La solución. Es un compromiso entre las fuerzas. La solución tiene los dos aspectos siguientes: • Estático o estructural, que se expresa en términos de componentes y relaciones entre los mismos. • Dinámico o de comportamiento, que describe las funciones de cada componente y cómo colaboran entre sí a lo largo del tiempo.
2.3.3. Clasificaciones de los patrones
Se admiten varios tipos de clasificaciones para los patrones. En concreto, se les puede clasificar según el nivel, el propósito o el ámbito: 1) En la clasificación por nivel, algunos autores hablan simplemente de patrones de diseño. Otros distinguen tres clases: • Patrones arquitectónicos. Se utilizan durante el diseño arquitectónico y tratan sobre la estructuración de un sistema de software en subsistemas. • Patrones de diseño propiamente dichos. Patrones dirigidos a resolver problemas puntuales del diseño. Diversidad de definiciones para patrón La inclusión de las frases hechas permite ver que no todos los autores entienden lo mismo por patrón, ya que algunas definiciones afirman que los patrones no tienen que estar vinculados a un lenguaje de programación.
• Frases hechas (idioms). Describen la manera de implementar algo (eventualmente un componente de un patrón de diseño) en un lenguaje de programación concreto.
© Editorial UOC
184
Ingeniería del software
2) La clasificación por propósito establece la jerarquía siguiente: • Patrones de creación. Se utilizan para la instanciación, con el fin de hacer que el software sea independiente de cómo las clases y objetos se crean, representan y agregan. Los patrones en el nivel de clase utilizan herencia para variar la clase, mientras que en el nivel de objetos se delega la instanciación a otro objeto. • Patrones de estructura. Hacen referencia a la manera como las clases y los objetos se combinan para formar estructuras mayores. En el nivel de clase se utiliza la herencia para agregar interfaz o implementación, y en el nivel de objetos se hace agregación en tiempo de ejecución. • Patrones de comportamiento. Describen la comunicación entre clases y objetos. En el nivel de clases se aplica la herencia y en el nivel de objetos, la agregación. 3) La clasificación por ámbito de los patrones identifica los siguientes: • Patrones sobre clases. Hacen referencia a las relaciones de herencia, que se establecen en tiempo de compilación. • Patrones sobre objetos. Hacen referencia a las relaciones entre objetos, las cuales pueden variar dinámicamente en tiempo de ejecución.
2.3.4. Un ejemplo de patrón: Composite
El patrón Composite* tiene como objetivo representar jerarquías de estructuras parte-todo. Este patrón se puede utilizar en los casos que se mencionan a continuación: a) Cuando se quieren representar jerarquías de tipo de agregación entre objetos. *. E. Gamma; R. Helm; R. Johnson; J. Vlissides (1995). Design Patterns. Addison-Wesley.
© Editorial UOC
185
Capítulo VI. Diseño orientado a objetos
b) Cuando se quiere que los clientes no necesiten distinguir entre objetos compuestos y no compuestos. Los clientes tratarán todos los objetos de la misma manera.
Las clases que figuran en esta estructura tienen las funciones siguientes: a) La clase Componente implementa el comportamiento de los objetos eventualmente compuestos y declara una interfaz para acceder a sus componentes y gestionarlos. b) La clase Hoja representa los objetos que no tienen componentes. c) La clase Composite define el comportamiento de los componentes que tienen componentes, y almacena estos últimos.
2.3.5. Sistemas de patrones
Ya se ha dicho que los patrones a menudo se refieren a otros patrones, ya sea porque se utilizan en su implementación, ya sea porque los complementan. Por tanto, más que de listas de patrones hablaremos de sistemas de patrones relacionados. La documentación de un sistema de patrones será algo más que la suma de la documentación de cada uno de los mismos: habrá que incluir también un esquema de las relaciones entre éstos y la descripción de las dependencias entre ellos cuando se utilizan juntos.
© Editorial UOC
186
Ingeniería del software
Algunas características deseables en un sistema de patrones son las que enumeramos a continuación: 1) Cantidad. El sistema de patrones debe tener un número suficiente de patrones de varias clases o niveles; de otro modo no se puede hacer diseño basado en patrones, sino sólo diseño ordinario utilizando algún patrón. 2) Descripción. Todos los patrones del sistema deben estar descritos de una manera tan uniforme como sea posible. 3) Relaciones. Las relaciones entre patrones tienen que estar indicadas explícitamente. 4) Organización. El catálogo de patrones del sistema debe estar organizado de manera que sea fácil encontrar el patrón más adecuado en cada caso. En particular, debe haber un sistema de criterios de clasificación como los descritos con anterioridad. 5) Practicidad. El sistema de patrones tiene que ser práctico, en el sentido de que se vea fácilmente cómo se pueden utilizar e implementar los patrones. 6) Acceso. El sistema tiene que ser abierto: debe ser posible que se integren con facilidad nuevos patrones, que se tienen que poder incorporar de manera natural al esquema de clasificación mencionado, y los patrones que ya existen se deben poder adaptar a los cambios tecnológicos. Cuando se habla de sistemas de patrones, se piensa principalmente en sistemas públicos, como los descritos en libros. No obstante, también puede haber sistemas para uso interno de una empresa o de un proyecto, que probablemente incluyan también patrones públicos. Los sistemas de patrones más conocidos son los que mencionamos a continuación: a) El de Gamma, Helm, Johnson y Vlissides.* b) El sistema de Buschmann, Meunier, Rohnert, Sommerlad y Stal. *. La Banda de los cuatro Los autores Gamma, Helm, Johnson y Vlissides se conocen de manera informal con el nombre de Gang of Four (La Banda de los cuatro).
© Editorial UOC
187
Capítulo VI. Diseño orientado a objetos
c) Los patrones documentados por Larman, que corresponden a principios generales de diseño más que a problemas específicos. Estos sistemas se publicaron en el mismo orden en el que se han mencionado, y cada sistema hace referencias a los anteriores. Por esta razón, creemos que se pueden considerar un solo sistema. Mencionamos todos los patrones en una única tabla que podéis ver a continuación. La descripción detallada de cada patrón se puede encontrar en las obras citadas en la bibliografía de este módulo. Nombre Abstract
Tipo
Sistema
Propósito
Creación
GHJV
Proporciona una interfaz para crear objetos relacionados sin que sea necesario saber su clase.
Adapter
Estructura
GHJV
Sustituye la interfaz de una clase, lo cual permite reutilizar algunas clases.
Blackboard
Arquitectónico
BMRSS
Coordina la comunicación entre los componentes de sistemas de software distribuidos.
Bridge
Estructura
GHJV
Desacopla una clase abstracta de su implementación para que puedan variar independientemente.
Builder
Creación
GHJV
Permite que la construcción de un objeto complejo pueda crear diferentes representaciones.
Chain of responsibility
Comportamiento
GHJV
Implementa llamadas de operaciones por medio de otros objetos.
ClientDispatcherServer
Estructura
BMRSS
Proporciona transparencia respecto a la ubicación y los mecanismos de conexión entre cliente y servidor.
Command
Comportamiento
GHJV
Command Processor
Comportamiento
BMRSS
Composite
Estructura
GHJV
Controller
Comportamiento
Larman
Asigna el tratamiento de los acontecimientos a las clases que representan el sistema o la organización en conjunto, o un papel o un caso de uso.
Creator
Estructura
Larman
Asigna a la clase B la responsabilidad de crear los objetos de otra clase A si B ya agrega, contiene, registra o usa de manera principal objetos de A o tiene la información para inicializarlos.
Factory
Convierte una llamada de una operación en un objeto que se puede manipular. Separa la petición de una operación de su ejecución con la finalidad de permitir deshacerla, por ejemplo. Construye una jerarquía de composición de objetos.
© Editorial UOC
Nombre
188
Tipo
Sistema
Ingeniería del software
Propósito
Decorator
Estructura
GHJV
Añade responsabilidades a un objeto dinámicamente, sin añadirlas a la clase.
Don’t call to Strangers
Comportamiento
Larman
Limita la variedad de objetos a los cuales pide operaciones un objeto dentro de la implementación de sus operaciones: sólo él mismo o un atributo suyo, los parámetros de la operación o los objetos creados dentro del método.
Expert
Comportamiento
Larman
Asigna cada operación a la clase que tienen los atributos que intervienen en la misma.
Facade
Estructura
GHJV
Proporciona una interfaz única a un subsistema con muchos objetos.
Factory Method
Creación
GHJV
Define una interfaz para instanciar un objeto, cuya clase se decide en el ámbito de subclases.
Flyweight
Estructura
GHJV
Permite que muchos pequeños objetos puedan ser compartidos haciendo que su estado sea independiente del contexto en que se usan.
ForwarderReceiver
Estructura
BMRSS
Aísla de los mecanismos de comunicación la comunicación entre procesos.
High Cohesion
Comportamiento
Larman
Asigna las operaciones a las clases de manera que la cohesión del diseño sea alta (es decir, que cada clase implemente un conjunto no demasiado grande de operaciones muy relacionadas).
Indirection
Comportamiento
Larman
Asigna una operación a una clase intermediaria para desacoplar la clase cliente de la servidora.
Interpreter
Comportamiento
GHJV
Representa las reglas de un lenguaje mediante clases.
Iterator
Comportamiento
GHJV
Accede a los componentes de un objeto agregado uno detrás de otro, sin ver su contenido.
Layers
Arquitectónico
BMRSS
Estructura una aplicación en grupos –de diferentes niveles– de subtareas.
Low Coupling
Comportamiento
Larman
Asigna las operaciones a las clases de manera que el acoplamiento entre las clases sea bajo, lo cual quiere decir que cada clase haga poco uso de operaciones de otras clases dentro de las suyas.
Master-Slave
Estructura
BMRSS
El maestro reparte trabajo a varios esclavos idénticos y obtiene el resultado final a partir de los resultados obtenidos por éstos.
Mediator
Comportamiento
GHJV
Define un objeto que encapsula la interacción de otros.
© Editorial UOC
Nombre
189
Tipo
Sistema
Capítulo VI. Diseño orientado a objetos
Propósito
Memento
Comportamiento
GHJV
Captura y externaliza el estado de un objeto (sin violar su encapsulación), para que pueda ser restituido más adelante.
Microkernel
Arquitectónico
BMRSS
Dentro de un software, separa un núcleo funcional de la funcionalidad añadida.
Model-ViewController
Arquitectónico
BMRSS
Descompone un software interactivo en tres componentes: el Modelo que contiene la funcionalidad y los datos, la Vista que presenta la información en la pantalla y el Controlador que trata las entradas de información.
Observer
Comportamiento
GHJV
Define una dependencia entre objetos de manera que cuando cambia el estado de un objeto se comunica el cambio a otros.
Pipes and Filters
Arquitectónico
BMRSS
Proporciona un estructura de tubos y filtros para tratar flujos secuenciales de datos.
Polymorphism
Comportamiento
Larman
Conviene aplicar el polimorfismo (dar el mismo nombre a operaciones análogas de clases diferentes) para que el objeto cliente no tenga que preguntar por la clase antes de pedirle la operación.
PresentationAbstractionControl
Arquitectónico
BMRSS
Descompone un software interactivo en una jerarquía de agentes que colaboran. Cada agente desempeña alguna función de presentación por pantalla, funcionalidad básica (abstracción) o comunicación entre agentes (control).
Prototype
Creación
GHJV
Instancia objetos haciendo copias de un prototipo.
Proxy (1)
Estructura
GHJV
Proporciona un representante para un objeto, que no hay que crear hasta que se necesite efectivamente. También puede controlar el acceso.
Proxy (2)
Estructura
BMRSS
Hace que los clientes de un componente pidan las operaciones a un representante de éste y no a él directamente, por razones de eficiencia, control de acceso u otras.
PublisherSubscriber
Comportamiento
BMRSS
Un publicador notifica sus cambios a varios suscriptores. Es una variante de Observer.
PureFabrication
Estructura
Larman
A veces conviene definir una clase que no corresponde a ninguna entidad del dominio, sino que es una “pura invención” para agrupar operaciones de manera más coherente que si estuvieran asignadas a clases de entidades.
Reflection
Arquitectónico
BMRSS
Proporciona un medio para cambiar dinámicamente la estructura y el comportamiento de un software.
Singleton
Creación
GHJV
Garantiza que de una clase sólo haya un objeto.
© Editorial UOC
190
Nombre
Tipo
Sistema
Ingeniería del software
Propósito
State
Comportamiento
GHJV
Hace que, cuando un objeto cambia de estado, cambie su comportamiento como si hubiera cambiado de clase.
Strategy
Comportamiento
GHJV
Encapsula varios algoritmos haciéndolos intercambiables.
Template Method
Comportamiento
GHJV
Define el esqueleto de un algoritmo de una operación, y algunos de sus pasos se concretarán en subclases.
View Handler
Comportamiento
BMRSS
Permite a sus clientes abrir, manipular y cerrar las presentaciones de los datos, y gestiona sus dependencias.
Visitor
Comportamiento
GHJV
Sustituye la interfaz de una clase, de forma que permite reutilizar algunas clases.
Whole-part
Estructura
BMRSS
Hace que una operación sobre los componentes de una estructura pueda cambiar sin que los componentes cambien de clase.
GHJV = Gamma, Helms, Johnson y Vlissides BMRSS = Buschmann, Meunier, Rohnert, Sommerlad y Stal
2.3.6. Los patrones para la ayuda en la resolución de problemas de diseño Los patrones sirven de ayuda a la hora de resolver problemas de diseño en los aspectos siguientes: a) Sugieren clases y objetos. b) Sugieren interfaces entre objetos, independientes de la implementación de los mismos, por ejemplo, mediante clases y operaciones abstractas. c) Ofrecen posibilidades de reutilización de código mediante superclases y objetos que se puedan utilizar como componentes de otros. d) Sugieren posibilidades de delegar operaciones de una clase a otra. e) Los sistemas de software son más fáciles de modificar por el hecho de que muchas veces los patrones se pueden implementar de varias maneras, manteniendo estables las interfaces. Más adelante, veréis el uso de varios patrones combinados para resolver un único problema.
© Editorial UOC
191
Capítulo VI. Diseño orientado a objetos
2.3.7. Selección del patrón adecuado
Para seleccionar el patrón adecuado en cada caso, hay que suponer que se dispone de un único sistema de patrones (si inicialmente se tenían varios, conviene consolidarlos) con un catálogo adecuado. El proceso de selección del patrón adecuado consiste en seguir los siguientes pasos: 1) En primer lugar, hay que especificar por escrito el problema que intentamos resolver con patrones, y si se ve que consta de partes bien diferenciadas, descomponerlo en subproblemas. De cada subproblema se tienen que describir las fuerzas que le afectan. 2) En segundo lugar, deberemos establecer una primera delimitación del conjunto de patrones aplicables mediante el catálogo. 3) A continuación, afinaremos más la selección teniendo en cuenta los objetivos de los patrones seleccionados antes. Interesarán tanto los patrones que contemplan todo el (sub)problema como también los que pueden resolver alguna parte. 4) Después, añadiremos a la selección todos los patrones relacionados directamente con los anteriores. 5) Entonces consideraremos los patrones que tienen como objetivo facilitar las modificaciones del software futuras, e incluiremos en la selección los que sean aplicables. 6) Más tarde, consideraremos las ventajas e inconvenientes descritos en la documentación, y evaluaremos qué importancia tienen en el caso considerado. 7) Finalmente, cuando un patrón seleccionado tenga variantes, seleccionaremos la más adecuada.
2.3.8. Utilización de un patrón
A continuación, se describe la manera de utilizar un patrón: 1) Se hace una lectura general de los puntos de la documentación del patrón que no se hubiesen leído todavía.
© Editorial UOC
192
Ingeniería del software
2) Se estudian con detalle los apartados sobre participantes, estructura y papel de los participantes. 3) Se estudia el ejemplo resuelto. 4) Se sustituye la terminología abstracta del patrón por la del proyecto y se establece una lista de equivalencias. 5) Se definen las clases nuevas necesarias, y se modifican las ya existentes que haga falta entre las que ya se habían definido durante el proyecto.
2.4. Marcos de aplicaciones Un marco (en inglés, framework), es un conjunto de clases que constituye una aplicación incompleta y genérica. Si el marco se complementa de manera adecuada (si se “especializa”), se obtienen aplicaciones especializadas de un cierto tipo. Hay dos tipos de marcos: 1) Un marco de caja blanca consta de un conjunto de clases (denominadas abstracciones) de las cuales está definida tanto la interfaz como la implementación. Para especializarlo, hay que implementar subclases de estas clases. 2) Un marco de caja negra, en lugar de abstracciones, tiene definidas unas interfaces denominadas papeles (en inglés, roles). Para especializarlo, hay que añadirle clases que implementen sus papeles.
2.4.1. Ventajas e inconvenientes de los marcos Algunas ventajas de los marcos son las que mencionamos a continuación: a) Reducen el trabajo de programación y mantenimiento de aplicaciones. Los marcos reducen la codificación y la puesta a punto, ya que proporcionan subsistemas que sabemos que funcionan. En definitiva, suministran código que ya no se deberá volver a escribir ni a mantener. b) Proporcionan una arquitectura para el software. c) Llevan a desarrollar pequeñas aplicaciones que encajan dentro de los marcos, en lugar de aplicaciones monolíticas.
© Editorial UOC
193
Capítulo VI. Diseño orientado a objetos
d) Son una buena base para la industria de componentes de software. Los marcos bien diseñados permiten que terceras compañías puedan suministrar componentes o partes de componentes que los desarrolladores podrán añadir. Como inconvenientes de los marcos, podemos enumerar los siguientes: a) Limitan la flexibilidad. Los componentes que se construyan para un marco tienen que amoldarse a las restricciones impuestas por la arquitectura de éste. b) Dificultan el aprendizaje. Antes de utilizar un marco para construir aplicaciones, hay que estudiarlo a fondo. Para este aprendizaje, se puede calcular un tiempo inicial de tres semanas (para un marco de complejidad media) más un tiempo adicional con un plazo medio determinado por la arquitectura de la aplicación que hay que construir. De todos modos, este aprendizaje sólo se tiene que hacer una vez y puede servir para muchas aplicaciones basadas en el marco. c) Reducen el grado de creatividad del trabajo de los desarrolladores.
2.4.2. Comparación entre marcos y patrones Finalmente, estableceremos una comparación entre los marcos y los patrones. Esta comparación se centra en los siguientes aspectos: 1) Los patrones son menores. Un marco puede contener varios patrones, nunca lo contrario. 2) Los patrones son más abstractos. Cada vez que se aplica un mismo patrón, produce programas diferentes. 3) Los patrones son menos especializados, ya que se pueden utilizar en cualquier tipo de aplicación.
3. El diseño arquitectónico
El diseño arquitectónico tiene como objetivo definir las grandes líneas del modelo del diseño.
© Editorial UOC
194
Ingeniería del software
El diseño arquitectónico comprende las actividades siguientes: establecer la configuración de la red, decidir la utilización de un marco ya disponible, si procede, y establecer los subsistemas, sus interfaces y las dependencias entre éstos.
3.1. Establecimiento de la configuración de la red
El establecimiento de la configuración de la red consiste en determinar los nodos que habrá y las características que tendrán, las conexiones entre éstos y cómo serán, y los protocolos de comunicaciones en cuanto al ancho de banda, fiabilidad y calidad.
3.2. Establecimiento de los subsistemas
Los subsistemas pueden ser propios del proyecto, reutilizados por otros proyectos o software del mercado, como software de sistemas y software intermediario o middleware. Se puede partir de la descomposición del software en paquetes hechos en la etapa de análisis. Las modificaciones que se harán en el mismo normalmente consistirán en segregar algún subsistema de un paquete de servicio con vistas a reutilizarlo en varios lugares del software, o a separar en subsistemas diferentes lo que ya está hecho de lo que se tiene que llevar a cabo en el proyecto, o a permitir que se reparta un paquete entre varios nodos. También conviene tener en cuenta la posibilidad de aplicar patrones arquitectónicos. Por interfaz de un subsistema entendemos las operaciones que se pueden pedir al subsistema desde otros subsistemas. Ahora bien, aparte de estas interfaces, no necesariamente definidas de manera explícita, para conseguir un diseño más flexible de cara a modificaciones futuras, puede ser conveniente definir interfaces explícitas implementadas por subsistemas que se pueden ir sustituyendo a lo largo del tiempo, igual que en el caso de interfaces de clases considerado de manera estándar en el UML.
© Editorial UOC
195
Capítulo VI. Diseño orientado a objetos
Es especialmente importante definir interfaces para los subsistemas que corresponden a software del sistema o a middleware, aunque hay que esperar a que vayan evolucionando a lo largo del tiempo de una manera independiente del software que desarrollamos. Las dependencias entre subsistemas se presentan cuando hay elementos de un subsistema que tienen relaciones con elementos de otro. Como mínimo, habrá todas las dependencias que ya existen entre los paquetes de análisis y de servicios correspondientes.
4. El diseño de los casos de uso
Dado que los requisitos se recogieron esencialmente en forma de casos de uso, una manera lógica de enfocar el diseño es describir la implementación de cada uno, partiendo de la versión revisada y documentada con diagramas de interacción obtenida en la etapa de análisis. El diseño de la implementación de los casos de uso (que a partir de ahora denominaremos simplemente diseño de los casos de uso) parte del diagrama de colaboración resumido que se ha hecho en el análisis, y se consideran por separado las clases de frontera, de entidades y de control. Las clases de frontera son el punto de partida del diseño de la interfaz de usuario. El diseño de las clases de entidades incluye el diseño de los instrumentos para gestionar la persistencia. No hablaremos aquí del diseño de la interfaz con el usuario y de la persistencia, sino en otros apartados. La implementación de la funcionalidad de los casos de uso se hace dentro de las clases de control y las clases de entidades. Dado que esta funcionalidad puede ser extremadamente variada, sólo se pueden dar algunas reglas generales sobre su distribución entre clases y las operaciones de éstas: a) Conviene que una de las clases de control dirija todo el proceso del caso de uso. b) Hay que aprovechar las oportunidades de reutilizar componentes y aplicar patrones. En lo que respecta a las otras formas de reutilización, el uso de
© Editorial UOC
196
Ingeniería del software
marcos ya se habrá considerado durante el diseño arquitectónico y la posibilidad de reutilización de clases se estudia de forma sistemática más adelante. Sin embargo, si se encuentran posibilidades obvias de reutilizar alguna clase, hay que hacerlo. El proceso del diseño de las clases de control es éste: se estudia la implementación de las operaciones ya identificadas en el análisis, una por una. A menudo ocurre que, para implementar una, son necesarias nuevas operaciones de clases ya definidas o también de clases nuevas. Después, habrá que estudiar la implementación de estas operaciones nuevas, etc. Como vemos, mientras se diseñan los casos de uso se van incorporando clases y operaciones nuevas al diagrama estático de análisis, que así llega a ser el diagrama estático de diseño. Una vez terminado el diseño de los casos de uso, será necesario revisarlo de la manera que describiremos más adelante, lo cual puede llevar a realizar retoques también en el diseño de los casos de uso.
5. Revisión del diagrama estático de diseño
Como ya hemos visto, la obtención del diagrama estático de diseño no es un paso independiente, sino que se va haciendo esencialmente durante el diseño de los casos de uso. Una vez acabado éste, queda hacer una revisión del diagrama obtenido. El diagrama revisado, juntamente con la especificación de las operaciones de sus clases, será la base para la implementación de las clases de control y de entidades.
Diferencias entre el diagrama estático de diseño y el de análisis
Generalmente, el diagrama estático de diseño contiene muchas más clases que el de análisis (ya hemos mencionado antes un factor típico de 5 a 1). No obstante, eso no
© Editorial UOC
197
Capítulo VI. Diseño orientado a objetos
quiere decir que el diagrama estático de diseño tenga todas las clases que tendrá el software una vez implementado. Dejando de lado las clases de la interfaz gráfica, si la herramienta utilizada está orientada a objetos, durante la programación se definirán muchas más clases que tendrán un papel puramente instrumental y que generalmente no se reflejan en un diagrama, ya que éste sería muy complejo (sin embargo, no se descarta hacer diagramas estáticos parciales si se cree conveniente).
La revisión del diagrama estático de diseño tiene en cuenta los aspectos siguientes: la normalización de los nombres, la reutilización de clases, la adaptación de la herencia en el ámbito soportado por el lenguaje de programación, la mejora del rendimiento, el incremento de la velocidad y la reducción del tránsito de mensajes mediante la agrupación de clases, la adición de clases temporales para almacenar resultados intermedios, y la revisión desde el punto de vista de cohesión y acoplamiento. Todas estas razones pueden justificar la modificación del modelo creado anteriormente, y lo haremos en un nuevo diagrama para respetar lo que hemos pactado con nuestro cliente.
5.1. Normalización de los nombres
En la recogida y documentación de requisitos es muy posible (e incluso recomendable) que hayamos utilizado la terminología del cliente para facilitar la comunicación con él. Por continuidad, seguramente será bueno utilizar la misma terminología en el diagrama estático del análisis y en la especificación formal de los casos de uso hecha dentro del análisis y, por tanto, en el diseño de los casos de uso. No obstante, incluso si se ha ido con cuidado de no utilizar nombres no soportados por los lenguajes de programación, puede ocurrir que haya que cambiar algunos nombres de clases, atributos y operaciones, bien porque vulneren alguna norma aplicable al proyecto o bien para respetar una terminología ya establecida en proyectos anteriores. Esto es importante de cara a la reutilización de clases, ya que la librería de clases puede contener muchas y pueden ser difíciles de encontrar, si no se usa una nomenclatura unificada.
© Editorial UOC
198
Ingeniería del software
5.2. Reutilización de clases
Durante el diseño de los casos de uso, las clases se hacen “a medida” de acuerdo con las operaciones que deben contener, y sólo se reutilizan clases cuando la posibilidad de hacerlo es obvia. Ahora se trata de revisar sistemáticamente las posibilidades de reutilizar clases ya existentes de acuerdo con lo que sabemos.
5.3. Adaptación de la herencia en el nivel soportado por el lenguaje de programación
La herencia múltiple se da bastante a menudo en diagramas estáticos de análisis, pero hay lenguajes de programación que no la soportan, y por esta razón, cuando se pretende realizar la implementación con uno de estos lenguajes, en el diagrama estático de diseño hay que sustituir los casos de herencia múltiple por otra estructura equivalente. Justificación del uso de la herencia múltiple Se podría pensar que, si sabemos que la aplicación se tiene que desarrollar en un lenguaje que no soporta la herencia múltiple, lo mejor es evitarla desde el principio, de la misma manera que se recomienda que los nombres respeten las restricciones más habituales en los lenguajes de programación. No obstante, utilizar la herencia múltiple cuando proceda puede hacer que el diagrama estático de análisis sea mucho más comprensible.
Para deshacer la herencia múltiple, habrá que utilizar alguna de las técnicas que describimos a continuación. En todos los casos nos referiremos al mismo ejemplo:
© Editorial UOC
199
Capítulo VI. Diseño orientado a objetos
5.3.1. Supresión de la herencia múltiple por duplicación
Una manera de suprimir la herencia múltiple consiste en duplicar en la subclase los atributos que heredaría de una de las superclases:
5.3.2. Supresión de la herencia múltiple por delegación
La herencia múltiple se puede suprimir por delegación si se mantiene una sola de las superclases y se incluye dentro de la subclase una referencia a un
© Editorial UOC
200
Ingeniería del software
objeto de la otra superclase, que tiene el valor de los atributos correspondientes:
5.3.3. Supresión de la herencia múltiple con interfaces
También se puede suprimir la herencia múltiple si se sustituye la herencia doble por herencia simple más una interfaz implementada por otra superclase:
5.3.4. Supresión de la herencia múltiple por agregación
Las relaciones de herencia se pueden sustituir por agregaciones. Esto se puede hacer de dos maneras:
© Editorial UOC
201
Capítulo VI. Diseño orientado a objetos
5.4. Sustitución de las interfaces
Si el lenguaje de programación no soporta las interfaces, se pueden sustituir por clases abstractas, de las cuales, como sabemos, las interfaces son un caso particular.
5.5. Cambios para la mejora del rendimiento
En el análisis normalmente no nos preocupamos por la cuestiones de eficiencia, pero en el diseño es imprescindible. Se pueden realizar cambios en el diagrama estático de diseño simplemente por esta razón.
5.5.1. Agrupación de clases para reducir el tránsito de mensajes
Hemos visto que, por flexibilidad, es mejor sustituir los atributos con valores múltiples por una clase aparte que comparta con la primera una asociación de n
© Editorial UOC
202
Ingeniería del software
a 1. Pues bien, por razones de eficiencia quizá es conveniente realizar el cambio a la inversa, ya que así no hay que enviar un mensaje de una clase a otra.
5.6. Especificación de las operaciones implícitas
En todos los proyectos o en casi todos, hay operaciones que permanecen implícitas dentro de las especificaciones del análisis. Dado que se deberán implementar igual que las otras, también conviene tenerlas en cuenta en la fase de diseño. Indicamos a continuación algunas reglas que nos pueden servir de ayuda a la hora de encontrar operaciones implícitas: 1) Para toda clase debe haber una operación que la instancie, otra que destruya los objetos y operaciones que lean y que pongan los valores de todos los atributos (naturalmente, quizá estas acciones queden comprendidas dentro de operaciones que realizan más acciones). La operación que crea un objeto agregado tiene que inicializar a nulo la lista de sus componentes. 2) Para cada asociación debe haber una operación que cree un enlace entre objetos y otra que lo recorra. 3) Para cada estado que puedan tener los objetos de una clase tiene que haber una operación que los haga llegar a este estado. 4) Para cada atributo derivado tiene que haber una operación que calcule su valor.
5.7. Referencias a las clases de frontera
Sabemos que las clases de control piden operaciones a las clases de frontera. Estas clases son provisionales y se sustituyen por elementos gráficos (generalmente también en forma de clases) durante el diseño de la interfaz de usuario. A menos que éste se hubiera llevado a cabo antes del diseño de los casos de uso, dentro de la especificación de las operaciones de las clases de control habrá que sustituir las llamadas operaciones de las clases de frontera por operaciones en elementos de la interfaz de usuario.
© Editorial UOC
203
Capítulo VI. Diseño orientado a objetos
5.8. La clase inicial
Generalmente, se crea un objeto cuando lo pide una operación que se ejecuta en relación con otro objeto ya existente, pero es obvio que tiene que haber un primer objeto que no es creado por ningún otro. Este mecanismo, que varía según el lenguaje de programación, se tiene que prever en el diseño.
5.9. Cohesión y acoplamiento
Llega un momento en el cual estamos razonablemente seguros de que el diagrama estático tiene todas las clases que deberá tener para la implementación y que todas estas clases tienen definidas todas las operaciones. Entonces conviene revisar este diagrama desde el punto de vista de la cohesión y el acoplamiento para dar la máxima flexibilidad al diseño, de cara a cambios futuros.
5.9.1. Cohesión
Una clase muy coherente lo es si sus atributos y operaciones tienen mucha relación entre sí, hasta el punto de que se puede considerar que forman una unidad. En cambio, una clase poco coherente agrupa atributos u operaciones que no tienen nada o casi nada que ver los unos con los otros, a menudo como consecuencia del hecho de que la clase implementa lo que en realidad son dos entidades más o menos autónomas. Una operación poco coherente es la que no tiene un proceso con un objetivo único y claro. Las clases y las operaciones poco coherentes son más difíciles de entender, y además tienen los siguientes inconvenientes: Uso de clases y operaciones poco coherentes A veces, no hay más remedio que agrupar varios procesos independientes, que no son propios de ninguna clase, en una sola. Por eso, existen las clases de utilidad del UML y el patrón Pure Fabrication.
© Editorial UOC
204
Ingeniería del software
• Presuponen que las varias entidades que representan están en relación de 1 a 1, lo cual no siempre es cierto. • Puede suceder que se tengan que especializar según diferentes criterios. • Se ven afectadas por más modificaciones. En general, interesa evitar las clases y operaciones poco coherentes. La cohesión de las clases se puede conseguir si se trasladan a éstas las reglas utilizadas en la normalización de bases de datos relacionales. Por otro lado, es conveniente descomponer en distintas operaciones, de la misma clase o de varias, las operaciones poco coherentes, de manera que cada una tenga un propósito concreto.
5.9.2. Acoplamiento
El acoplamiento de las clases y de los objetos expresa el grado en que éstos dependen de otras clases y objetos para llevar a cabo su responsabilidad. Cuanto más acoplamiento tenga una clase, más se verá afectada por cambios en otras y, por tanto, se deberá modificar más a menudo. Existen varias formas de acoplamiento: 1) Acoplamiento por referencia. Acoplamiento en el cual un objeto contiene una referencia a otro. Se puede reducir si se suprimen asociaciones o si las referencias se hacen unidireccionales. 2) Acoplamiento por representación. En este tipo de acoplamiento, un objeto utiliza otro. El acoplamiento por representación puede tener varios grados: el acceso directo a atributos públicos (el grado más bajo), la petición mediante operaciones de los valores de los atributos (privados) para evaluar un resultado, o la llamada a una operación que dé este resultado ya calculado (el grado más alto). 3) Acoplamiento por subclases. Acoplamiento en el que una clase A tiene una asociación con cada una de las subclases o les pide operaciones. Para extenderlo a una subclase nueva, habría que modificar la clase A. En cambio, el acoplamiento es menor si la asociación o las llamadas desde operaciones se dirigen a la superclase, ya que no hay que modificar A por el hecho de que se añadan subclases. En este caso, habría problemas si la asociación o la operación no se tuvieran que extender a la subclase nueva.
© Editorial UOC
205
Capítulo VI. Diseño orientado a objetos
El acoplamiento es todavía más bajo si las llamadas a operaciones se dirigen a una interfaz, ya que entonces se podría incluso sustituir la superclase sin tener que modificar la clase A, siempre que la nueva clase implementara la misma interfaz. 4) Acoplamiento por herencia. La subclase no puede prescindir de los atributos y operaciones que hereda de la superclase. En cambio, esto sí que es posible si se sustituye la herencia por la agregación.
6. Diseño de la persistencia
Cuando un proceso acaba, libera la memoria que utilizaba y todo lo que había, en principio, se pierde. Si un objeto debe tener una vida más larga que el proceso que lo crea o, dicho de otra manera, el objeto se crea en un proceso y se utiliza en procesos posteriores, hay que grabarlo en un sistema de almacenamiento permanente. Entonces se dice que dicho objeto se ha hecho persistente y se habla de un objeto persistente. Denominamos clases persistentes a las clases que pueden tener objetos persistentes, y clases temporales a las no persistentes. En relación con un objeto persistente, tiene que ser posible llevar a cabo al menos dos operaciones: grabarlo y leerlo (la operación ‘leer’ también se conoce como ‘materializar’). En la práctica también será necesario poderlo borrar e identificar entre los otros objetos persistentes de la misma clase. De un objeto, se graban los valores de los atributos (es decir, lo que se denomina estado del objeto). Ahora bien, es posible que no todos los atributos de un objeto persistente sean persistentes. El estado persistente del objeto en cuestión lo constituyen los valores de los atributos que se hacen persistentes. Los objetos persistentes de una clase se pueden leer de dos maneras: o bien todos a la vez al comienzo del proceso, o bien cada uno cuando es necesario (modalidad de materialización según demanda). Podemos distinguir tres tipos de sistemas de almacenamiento según la manera como se implementa la persistencia: bases de datos orientadas a objetos, bases de datos relacionales y ficheros clásicos, y bases de datos object-relational.
© Editorial UOC
206
Ingeniería del software
6.1. Persistencia con bases de datos orientadas a objetos
La implementación de la persistencia con bases de datos orientadas a objetos es el caso más sencillo de todos, ya que no hay que transformar los objetos para hacerlos persistentes. No es necesario hacer un diseño de la persistencia: para especificar que los objetos de una clase pueden ser persistentes, sólo hay que enriquecer la definición de la clase, indicando cuáles de los atributos son persistentes y qué política de lectura de objetos se quiere seguir (se leen todos de una vez, o según demanda). Cálculo automático de los atributos no persistentes El sistema de gestión de bases de datos calculará de manera automática los atributos al materializar los objetos.
A partir de las definiciones de las clases enriquecidas de esta manera, se genera código que se pasa a un preprocesador que le añadirá los métodos necesarios para gestionar la persistencia de los objetos.
6.2. El modelo para bases de datos relacionales y ficheros clásicos: alternativas
En el modelo para bases de datos relacionales y ficheros clásicos, a un objeto le corresponde, en principio, una fila de una tabla de una base de datos relacional o un registro de un fichero, respectivamente y a los atributos de los objetos les corresponden columnas de la tabla correspondiente. Hay que realizar la transformación mencionada antes de grabar un objeto, y es preciso llevar a cabo la transformación inversa antes de que sea posible utilizarlo una vez leído. Con este sistema de almacenamiento existen tres maneras de llevar a cabo la gestión de la persistencia: 1) Hacer que cada clase persistente tenga operaciones para que los objetos se graben, borren, etc., por sí mismos. Esta opción tiene la ventaja de que es más
© Editorial UOC
207
Capítulo VI. Diseño orientado a objetos
eficiente que las otras, dado que requiere menos llamadas entre objetos, pero tiene el inconveniente de que la implementación de las clases persistentes dependerá de un sistema de gestión de bases de datos concretos por el hecho de que son clases de entidades que corresponden a entidades del dominio del software, lo cual limita la portabilidad de la aplicación. 2) El segundo método define una clase denominada gestor de disco para cada clase persistente. El gestor de disco accede directamente al fichero o base de datos. Con este método, la clase de entidades se desacopla del sistema de gestión de base de datos, y tiene la ventaja adicional de que el gestor de disco puede hacer de memoria caché de los objetos de la clase de entidades (si los objetos leídos se materializan dentro de instancias del gestor antes de crear instancias de la clase de entidades). Ahora bien, esta solución es menos eficiente que la anterior. 3) El tercer método es una mezcla de los anteriores y consiste en crear los gestores de disco y además añadir operaciones de grabación, lectura, etc., a las clases del dominio. La diferencia con el primer método es que las operaciones de la clase no implementan la persistencia directamente, sino que llaman operaciones del gestor de disco. Con el fin de aislar las clases de entidades del sistema de gestión de bases de datos, es muy útil implementar la persistencia por medio de un marco.
6.2.1. Obtención de la definición de la estructura de base de datos relacional o de ficheros clásicos
La base de partida para obtener la definición de la estructura de bases de datos relacional o de ficheros clásicos es la parte del diagrama estático de diseño que contiene las clases de entidades que son clases persistentes, y las relaciones entre éstas. Los pasos para llegar a obtener la definición de esta estructura serán los siguientes: 1) Transformar el modelo estático en un modelo entidad-relación (modelo ER).
© Editorial UOC
208
Ingeniería del software
2) Suprimir la herencia, dado que el modelo relacional no la soporta. Si el modelo ER utilizado tampoco la soporta, este paso se habrá debido hacer antes del anterior. 3) Transformar el modelo ER en un modelo relacional según las reglas habituales del diseño de bases de datos relacionales. En el caso de ficheros clásicos, en lugar de tablas relacionales tendremos ficheros planos. 4) Crear un gestor de disco para cada clase persistente que implemente los accesos a las tablas o ficheros planos correspondientes.
6.2.2. Transformación del modelo estático en el modelo ER
Si nos fijamos, un modelo OO es muy parecido a un modelo ER, sobre todo en el caso de las variantes del modelo ER que soportan la herencia de tipo de entidades. En este caso, la transformación del modelo estático en el modelo ER consiste en convertir cada clase con un atributo con valores múltiples en dos clases unidas por una asociación, y después hacer corresponder un tipo de entidad a cada clase no asociativa. Más tarde, se añade una relación para cada asociación o clase asociativa o agregación, con cardinalidades que son obvias. Cuando la supresión de la herencia se lleva a cabo al pasar del modelo estático al modelo ER, el término tablas hace referencia a entidades y relaciones. Al pasar del modelo ER al relacional, el concepto clases se refiere a entidades y relaciones.
6.2.3. Supresión de la herencia
Supondremos el caso presentado en la siguiente figura:
© Editorial UOC
209
Capítulo VI. Diseño orientado a objetos
Hay tres formas de resolver la situación planteada: 1) Definir una tabla para cada clase, que contendría tanto los atributos propios de la clase como los heredados. 2) Crear una tabla para la superclase y una complementaria para cada subclase de ésta que tenga atributos propios. Cada tabla complementaria contendría los atributos propios de la subclase respectiva más los atributos que identifican cada fila (es decir, cada objeto) dentro de la tabla de la superclase para juntar todos los atributos (heredados y no heredados) de cada objeto de la subclase. Nota terminológica Cuando la supresión de la herencia se lleva a cabo al pasar del modelo estático al modelo ER, el término tablas hace referencia a entidades y relaciones. Al pasar del modelo ER al relacional, el concepto clases se refiere a entidades y relaciones.
3) Crear una sola tabla para toda la jerarquía de clases, que tendría los atributos propios de cada subclase más los de la superclase. En cada fila, todos los atributos que no fuesen aplicables a la subclase a la que pertenece el objeto deberían tener el valor nulo. Supresión de la herencia por definición de una tabla para cada subclase
Al definir una tabla para cada clase, las filas de Cliente_Especial tendrán tanto los atributos específicos de Cliente_Especial como los heredados. Tabla Cliente: NIF: String, clave principal Nombre: String ... Tabla Cliente_Especial: NIF: String, clave principal Nombre: String Descuento: Integer ...
© Editorial UOC
210
Ingeniería del software
Evidentemente, esta solución es muy sencilla, pero tiene los siguientes inconvenientes:
• Hay tantas tablas como subclases. • Hay que crear un gestor de disco para cada subclase. • Un cambio en la definición de Cliente obligaría a cambiar los gestores de disco de todas las subclases. • Complicará los procesos que tengan que tratar todos los clientes, ya que será necesario realizar una fusión de todas las tablas.
Supresión de la herencia por creación de una tabla para la superclase y una complementaria para subclase
Para suprimir la herencia, también se puede crear una tabla para la superclase en la que se graba a todos los clientes. Al mismo tiempo, crearemos una tabla complementaria para cada subclase con el identificador del objeto y los atributos específicos de la subclase. Un gestor de disco único se encargará de leer y hará un join por identificador entre las diferentes tablas con la finalidad de obtener toda la información de cada clase. Según la información que lea, el gestor creará una instancia de una subclase u otra y la llenará con sus datos.
Tabla Cliente: NIF: String, clave principal Nombre: String ... Tabla Auxiliar Cliente_Especial: NIF: String, clave principal Descuento: Integer ...
Esta solución puede ser la mejor opción si sólo una fracción pequeña de los objetos de la clase pertenecen a la subclase y, además, los valores de los atributos
© Editorial UOC
211
Capítulo VI. Diseño orientado a objetos
de ésta son de longitud fija, ya que entonces los valores nulos ocuparían mucho espacio, si hubiera para todos los objetos de la superclase.
Supresión de la herencia por creación de una tabla única para toda la jerarquía de herencia
Esta tercera solución es más eficiente en tiempo, pero menos en ocupación de disco. La supresión de la herencia por creación de una tabla única para toda la jerarquía de herencia consiste en crear una sola tabla con todos los campos, tanto de la superclase como de todas sus subclases, y añadirle un campo que nos diga qué subclase del objeto corresponde a cada fila.
Tabla Cliente: NIF: String, clave principal Tipo: Integer Nombre: String ... Descuento: Integer ....
donde Tipo se define de la siguiente manera:
Tipo =
⎧ 0 si es Cliente ⎨ ⎩ 1 si es Cliente_Especial, etc.
Esta solución puede ser buena cuando el espacio ocupado por los valores nulos de los atributos no aplicables a todas las subclases sea reducido. Es decir, si hay pocas subclases, éstas tienen pocos atributos propios o bien casi todos los atributos son aplicables a la mayoría de los objetos.
© Editorial UOC
212
Ingeniería del software
6.2.4. Los gestores de disco
Consideremos ahora el método alternativo del gestor de disco para la supresión de la herencia. El gestor de disco es una clase diferente de la clase persistente, y dentro de las operaciones de ésta hay llamadas a operaciones del gestor de disco. Consideraremos por separado el gestor de disco básico y los gestores de disco para la materialización según demanda. Diseño básico de gestores de disco
Podemos considerar que todos los gestores de disco tienen al menos unas operaciones básicas (leer, grabar, regrabar y borrar). Por tanto, podemos entender que todos son subclases de una superclase que denominaremos GestorGenerico, en la cual estas operaciones serían abstractas. Incluso podríamos considerar que hay unas subclases intermedias GestorRelacional y GestorFicheros, que serían superclase de todos los gestores relacionales y de todos los gestores de ficheros clásicos, respectivamente. En el diseño básico de gestores de disco puede aplicarse el patrón Template Method, en el cual hay una superclase abstracta que tiene una operación concreta que llama operaciones abstractas de sí misma, las cuales llegan a ser concretas en las subclases. El diagrama de clases correspondiente a este diseño es como el que veis a continuación (el parámetro id es de tipo string por todas partes): La clase abstracta GestorGenerico tiene la operación leerId (entre otras operaciones públicas para borrar, etc.) que lee un objeto a partir de un identificador del orientado a objetos mismo. En primer lugar, esta operación comprueba si el objeto ya está materializado y entonces lo coge de memoria (operación enCache). De otro modo, lo tiene que leer de la base de datos o fichero con la operación abstracta materializar. Esta operación llega a ser concreta en las subclases (también abstractas) GestorRelacional y GestorFicheros, y llama la operación leerFila o leerRegistro, respectivamente, y después, filaAObjeto o registroAObjeto, también de forma respectiva, que hacen los movimientos de datos entre la fila o registro leído y el objeto creado (de una clase concreta). Por tanto, estas operaciones dependen de cuál sea la clase persistente y, en consecuencia, son abstractas.
© Editorial UOC
213
Capítulo VI. Diseño orientado a objetos
Las operaciones leerFila y leerRegistro también dependen de la tabla o fichero que se debe leer, que podría ser un parámetro adicional de la operación (por ejemplo, si se utiliza una técnica de acceso como SQL dinámico) o debería ser sustituida en el nivel de subclase por medio de polimorfismo. Esto último se debería hacer necesariamente si la materialización requiriese acceder a más de una tabla o fichero. El proceso para añadir o modificar una fila es simétrico del de materializar: en GestorGenerico y en GestorRelacional hay una operación grabar abstracta y GestorFicheros llama dos operaciones: objetoAFila y grabarFila, y objetoARegistro y grabarRegistro, respectivamente. Si la fila o registro existe, se sustituyen sus valores, y si no, se añade a la tabla. También habría que prever una operación para borrar filas o registros uno por uno.
© Editorial UOC
214
Ingeniería del software
Para implementar la materialización según demanda, se puede utilizar una combinación del patrón Template Method con la modalidad denominada Virtual del patrón Proxy más los patrones Factory Method y Singleton. Diseño de gestores de disco para la materialización según demanda
Este diseño es evidentemente más complejo y sólo está justificado o bien cuando debe ser posible sustituir la clase de entidad sin tener que modificar todas las que la utilizan, o bien cuando la materialización es costosa y hay que esperar a hacerla cuando sea absolutamente necesario. Sin embargo, mientras no se haga, es necesario que las referencias exteriores al objeto apunten a un objeto existente. Las referencias exteriores no se hacen a objetos de la clase de entidades en cuestión, sino a objetos de una clase sustituta. La clase original y la sustituta implementan la misma interfaz (o clase abstracta, si el lenguaje de programación no soporta explícitamente las interfaces), y la clase sustituta llama las operaciones del original. La clase sustituta puede ser subclase de una clase abstracta. Antes de pedir operaciones al gestor de disco, hay que crear una instancia. Obviamente, la instancia que se tiene que crear debe ser del gestor de disco correspondiente a la clase de entidades en cuestión y a su sustituta. El patrón Factory Method define una clase creadora abstracta (que puede ser la clase sustituta abstracta) y crea una instancia de la clase adecuada con una operación abstracta de creación. Esta operación es sustituida por operaciones concretas en el nivel de subclases que crean instancias del gestor correspondiente. Lectura recomendada Encontraréis ampliaciones sobre el diseño de gestores de disco para la materialización según demanda que consideran otros aspectos de la persistencia (por ejemplo, transacciones) con más patrones en la siguiente obra: C. Larman (1998). Applying UML and Patterns. An Introduction to Object-Oriented Analysis and Design. Prentice Hall.
La aplicación del patrón Singleton garantiza que sólo se cree una instancia de cada clase gestor, y lo consigue haciendo que la instancia creada sea el valor de un
© Editorial UOC
215
Capítulo VI. Diseño orientado a objetos
atributo de clase y la operación de creación sea una operación de clase, mientras que el estado del objeto se compone de atributos de instancia y es accesible por medio de operaciones de instancia.
6.3. Persistencia con bases de datos object-relational
En principio, el método diseño de la persistencia con bases de datos objectrelational es el mismo que el de las bases de datos relacionales, con la diferencia de que este nuevo modelo puede tener atributos de tipo compuesto y, por tanto, no será necesario crear gestores de disco para todas las clases persistentes, sino sólo para aquéllas a las cuales se accederá directamente. Ejemplo de diseño de persistencia con bases de datos object-relational En el ejemplo de una clase Persona con hijos, si la base de datos que utilizamos permite tener como campo un array de hijos, modelaremos esta relación como un atributo de persona y evitaremos tener que definir un gestor de disco de hijos. Decimos “si permite” porque de momento no existe ningún estándar y cada fabricante de sistemas de gestión de bases de datos ofrece un modelo propio. Por tanto, se tendrá que ir con cuidado al escoger una base de datos de este tipo para que satisfaga las necesidades de nuestra empresa.
© Editorial UOC
216
Ingeniería del software
7. Diseño de la interfaz gráfica de usuario
En las etapas de recogida y documentación de requisitos había un cierto paralelismo entre las actividades relativas a la funcionalidad y las relativas a la interfaz de usuario: en la recogida y documentación de requisitos había casos de uso, por un lado, y tareas, por el otro. En la etapa de análisis, había colaboración entre clases de frontera, de control y de entidades, por una parte, y esquema del aspecto visual de las clases de frontera, por la otra. La razón de esta dualidad es clara: cuando se trata de la funcionalidad, se considera el funcionamiento del software desde el punto de vista interno, mientras que cuando se trata de la interfaz, lo que cuenta son los efectos del funcionamiento del software visibles por el usuario. En la etapa de diseño esta dualidad se mantiene por dos motivos: • Por un lado, por la razón ya mencionada. Hay un diseño de la interfaz de usuario separado del diseño de los casos de uso. • Por otro lado, como veremos a continuación, porque en el diseño de la interfaz de usuario se utiliza una metodología diferente en muchos aspectos. También es posible que al comienzo de la implementación se trabaje por separado en la funcionalidad y en la interfaz de usuario, pero en algún momento se tendrán que juntar las clases de la interfaz gráfica con el resto, puesto que deberán colaborar. La coherencia entre la funcionalidad y la interfaz de usuario debería estar garantizada por el hecho de que las bases de partida de los desarrollos respectivos (la documentación de los casos de uso y la de las tareas futuras, ambas obtenidas en la etapa de recogida y documentación de requisitos) describen lo mismo desde dos puntos de vista. Sin embargo, está claro que conviene comprobar que esta concordancia se mantenga entre la documentación respectiva correspondiente a las etapas de análisis y de diseño. El diseño de la interfaz de usuario considera tres aspectos de ésta: a) El contenido, que ya está establecido en los esquemas de las ventanas elaborados en el análisis.
© Editorial UOC
217
Capítulo VI. Diseño orientado a objetos
b) El formato, que se especifica íntegramente en esta fase. c) La interacción, es decir, la dinámica de la interfaz de usuario, denominada también diálogo entre el usuario y el sistema. La interacción está establecida dentro de la especificación de los casos de uso en términos formales (clases de frontera), pero independientes de la herramienta que se utilizará. Por tanto, en el diseño deberá describirse la implementación con los elementos que ofrece la herramienta de apoyo de la interfaz gráfica. Antes de entrar en el diseño de la interfaz gráfica de usuario propiamente dicho, veremos brevemente los aspectos estáticos y dinámicos de la interfaz gráfica de usuario, que son los elementos con los cuales se elabora el diseño. La interfaz gráfica de usuario es sólo una parte de la interfaz de usuario en general: es únicamente la interfaz implementada por medio de pantallas gráficas con teclado y ratón. La interfaz gráfica de usuario no incluye, por tanto, las salidas impresas, en especial las alfanuméricas (los clásicos listados). Interfaces alfanuméricas Las interfaces alfanuméricas por pantalla son una reliquia de la época en que la unidad direccionable dentro de las pantallas no era el píxel, sino el carácter, y se pueden considerar un caso particular, muy simple, de las interfaces gráficas.
7.1. Elementos y funcionamiento de la interfaz gráfica de usuario
Comenzaremos por describir brevemente los principales tipos de elementos que componen las interfaces gráficas y después hablaremos de la interacción entre el usuario y el sistema.
7.1.1. Elementos de la interfaz gráfica de usuario Los elementos de las interfaces gráficas se acostumbran a denominar objetos u objetos gráficos.
© Editorial UOC
218
Ingeniería del software
Ejemplos de objetos gráficos Un objeto de la interfaz puede ser tanto una ventana como un botón, un texto, una palabra o un carácter dentro de un texto.
Los objetos gráficos no son necesariamente instancias de clases, aunque sí que lo son cuando la interfaz se implementa con una herramienta orientada a objetos. Es normal que un objeto de la interfaz esté formado por otros objetos. Los objetos gráficos se pueden basar en píxeles o en unos objetos que se denominan primitivas gráficas. Sin embargo, para visualizar e imprimir las primitivas gráficas generalmente hay que convertirlas en mapas de bits (rasterización). Una interfaz gráfica tiene los siguientes tipos de componentes: escritorio, cursores y punteros, ventanas, menús, controles, elementos complejos y cajas de diálogo. El escritorio
El escritorio es el fondo de pantalla que ve el usuario cuando se pone en marcha el sistema y también antes de poner en marcha alguna aplicación. Sobre él aparecen los objetos de la interfaz gráfica. Los dispositivos de entrada: ratón, teclado, pluma y pantalla táctil
Una interfaz gráfica utiliza dos dispositivos de entrada típicos: el teclado y el ratón. El puntero sigue el movimiento del ratón y cambia de forma según los usos: flechas de una, dos o cuatro puntas, cruz, reloj, etc. Tanto el puntero como los objetos que puede seleccionar tienen una zona alrededor dentro de la cual los clics tienen efecto. El ratón puede tener de uno a tres botones y se puede utilizar de cuatro maneras básicas:
• Arrastrar el puntero sin apretar ningún botón. • Pulsar el botón sobre un icono y dejarlo ir inmediatamente (hacer clic). • Pulsar el botón y arrastrar el icono antes de dejarlo ir.
© Editorial UOC
219
Capítulo VI. Diseño orientado a objetos
• Pulsar el botón y dejarlo ir dos veces seguidas o más sobre un icono (doble clic, etc.). Del teclado nos interesan especialmente las combinaciones de teclas que equivalen a la selección de opciones dentro de un menú. El cursor señala el punto, dentro de un campo o un texto, donde tiene efecto lo que se haga con el teclado. Se dice que el objeto donde está el cursor “tiene el foco”. La navegación del cursor se puede llevar a cabo haciendo clic con el ratón en la posición deseada, o con las teclas de principio de línea (Home), final de línea (End), retroceso de página (Page Up), avance de página (Page Down), las cuatro flechas y el tabulador (Tab). La pluma puede hacer las funciones del ratón, pero además puede escribir. Entonces, según la forma y dirección del trazo se ejecutan diferentes mandos: seleccionar, copiar/enganchar, anular, tabular, borrar un carácter, tecla de retorno de carro (Return), espacio, etc. Funciones equivalentes de la pluma y el ratón Marcar en un punto con la pluma equivale a hacer clic con el ratón, marcar dos veces equivale a hacer doble clic. Por otro lado, con la pluma se puede arrastrar como con el ratón.
Las pantallas táctiles son útiles cuando el volumen de datos que se tiene que introducir es muy pequeño y la entrada consiste esencialmente en selecciones. Las ventanas
Una ventana viene a ser una pantalla virtual asociada a una aplicación activa, y es un marco dentro del cual aparecen los objetos propios de la aplicación. Si en un momento dado hay varias aplicaciones activas en un ordenador con una sola pantalla física, y por tanto con un único escritorio, lo tienen que compartir, y la manera de hacerlo es que cada aplicación tenga su ventana (de hecho, una aplicación puede tener varias ventanas, como veremos). La ventana de la aplicación con la que trabaja el usuario en cada momento recibe la entrada del ratón y el teclado (se dice que “tiene el foco”) y a menudo
© Editorial UOC
220
Ingeniería del software
tapa de forma total o parcial las otras. Por el contrario, las ventanas de las otras aplicaciones activas permanecen en segundo plano, pero a punto para volver a aparecer cuando el usuario vuelva a trabajar con la aplicación respectiva. Hay dos maneras de gestionar el foco de las aplicaciones: 1) La gestión implícita del foco, en la cual la ventana que tiene el foco es siempre aquélla sobre la cual está el puntero del ratón. 2) La gestión explícita del foco, en la que la asignación del foco a una ventana se hace explícita e independientemente de la posición del cursor. En el caso más general, las ventanas tienen un marco y pueden llevar un título y contener elementos gráficos activos (controles) para las siguientes operaciones: • Variar su tamaño. • Maximizarla, que quiere decir hacer que ocupe toda la pantalla. • Minimizarla, convirtiéndola en un icono. Si se hace doble clic sobre la misma recupera las dimensiones que tenía antes de la minimización. • Restaurarla, es decir, restituirle las dimensiones que tenía antes de maximizarla. • Dividirla en dos, verticalmente u horizontalmente, arrastrando la línea de división. • Desplazar el contenido arriba y abajo y a la derecha y a la izquierda (scroll) por medio de las barras que hay a la derecha y debajo respectivamente. • Arrastrar toda la ventana, normalmente situando el cursor en la barra de título. • Esconderla (es decir, hacerla transparente, de manera que deje ver la ventana de debajo o el escritorio). • Cerrarla, acabando o no la aplicación respectiva. Podemos distinguir diferentes tipos de ventanas:
1) Ventanas de aplicación. Son las ventanas que aparecen cuando un usuario activa una aplicación. Tienen un título con el nombre de la aplicación, con-
© Editorial UOC
221
Capítulo VI. Diseño orientado a objetos
troles para redimensionarlas, el menú de barra de la aplicación, botones para maximizarlas, minimizarlas y cerrarlas, un área de mensajes y un área de estado, y son movibles.
Ventana de aplicación y menús En la figura podéis ver una ventana de aplicación y una cascada de menús: el menú de barra y dos niveles de menús desplegables.
2) Ventanas de documento. Son ventanas asociadas a una aplicación y generalmente dentro de la ventana de ésta (observad la figura siguiente). Se crea una cada vez que se abre un documento o se crea un documento nuevo. Puede haber varias ventanas de documento abiertas al mismo tiempo, pero sólo una tiene el foco, incluso si hay varias visibles al mismo tiempo, es decir, el usuario en cada momento sólo puede trabajar con un documento. Tiene que haber alguna manera de pasar de un documento a otro: generalmente se selecciona de una lista o se hace clic en una porción visible.
© Editorial UOC
222
Ingeniería del software
Las ventanas de documento tienen un título con el nombre del documento, controles de ventana con las mismas opciones que la ventana de la aplicación y también controles para el desplazamiento (en inglés, scroll) horizontal y vertical y para dividir la ventana.
Ventana de documento y menú emergente Esta figura es un ejemplo de ventana de documento (en este caso, un diagrama) en la cual se ve también un menú emergente.
3) Ventanas de cajas de diálogo o ventanas secundarias. Tienen una barra de título con el nombre del mando que las ha abierto y contienen al menos una caja de diálogo. No tienen área para documentos, ni barras de menú y de estados, ni controles de redimensionamiento, ni área de mensajes; se pueden mover y redimensionar estirando para que haya más opciones visibles. Generalmente, son ventanas modales, es decir, mientras están abiertas, el usuario no puede trabajar con ninguna otra ventana de la misma aplicación o incluso, según en qué sistema operativo, de todo el sistema.
© Editorial UOC
223
Capítulo VI. Diseño orientado a objetos
Elementos estáticos
Los elementos estáticos son elementos fijos y pasivos contenidos dentro de una ventana o un control complejo: títulos y otras etiquetas, líneas, logotipos, dibujos que no sean iconos, etc. Controles simples
Los controles son los componentes activos de la interfaz por medio de los cuales el usuario interactúa con el software. Los hay simples y compuestos. Los principales tipos de controles simples son los que citamos a continuación: a) Botones de mandato. Acostumbran a ser cuadrados o rectangulares. A menudo van agrupados por funciones relacionadas. Para identificar su función, llevan un icono, un texto o ambos. Cuando se seleccionan, aparentan estar hundidos o presentan algún otro cambio de aspecto.
Ejemplos de botones de mandatos En la figura podéis ver un ejemplo de ventana modal con una caja de diálogo, carpeta con separadores y Check boxes.
© Editorial UOC
224
Ingeniería del software
b) Iconos. Son pequeños dibujos. Cuando no van asociados a botones, es posible hacer clic, doble clic y arrastrar / dejar (en inglés, drag and drop). c) Check boxes. Son casillas cuadradas que corresponden a una variable booleana. Cuando ésta toma el valor “verdadero”, la casilla aparece marcada. d) Botones de radio. Representan variables booleanas de las cuales sólo una puede ser cierta en cada momento, o bien valores posibles e incompatibles de una variable. Por tanto, en un grupo de botones de radio, hay siempre uno seleccionado, y sólo uno. En cambio, las check boxes son independientes.
Caja de diálogo y texto con scroll En la figura podéis observar una caja de diálogo con carpeta con separadores, un conjunto de botones de radio (Export Control) y un texto de posibles líneas múltiples con barra de desplazamiento vertical.
e) Value sets. Son como botones de radio, pero con iconos en lugar de etiquetas. Por ejemplo, las paletas de colores.
© Editorial UOC
225
Capítulo VI. Diseño orientado a objetos
f) Campos de texto. Un texto es un campo alfanumérico de longitud virtualmente ilimitada. Según la aplicación, un texto puede ser un documento o sólo el contenido de un control. En el último caso, el texto puede ser de una línea o de líneas múltiples con eventual barra de desplazamiento vertical y horizontal.
© Editorial UOC
226
Ingeniería del software
g) Spin boxes. Permiten dar un valor, o aumentarlo o disminuirlo por saltos haciendo clic en unos botones con puntas de flecha.
Listas desplegables y spin boxes En la figura se pueden ver ejemplos de listas desplegables (una está desplegada) y algunas spin boxes (Sangría izquierda, derecha y otras).
Controles complejos
Los controles complejos son los que están formados por otros controles. A continuación mencionamos algunos tipos de controles de esta clase:
a) Listas y listas combo. Sus elementos pueden ser etiquetas o, más raramente, iconos. En las listas combo se puede seleccionar un elemento existente o teclearlo; en cambio, en las listas ordinarias sólo es posible seleccionar un elemento existente. Las listas y listas combo pueden ser permanentes (con barras de desplazamiento o no) o desplegables (en este caso tienen un control para desplegarlas, normalmente un botón con una punta de flecha hacia abajo).
© Editorial UOC
227
Capítulo VI. Diseño orientado a objetos
b) Tablas o matrices. Así como las listas son unidimensionales, las tablas o matrices son bidimensionales y se organizan en celdas.
c) Cajas de diálogo. En este contexto, un diálogo es un intercambio de símbolos y acciones entre el sistema y el usuario. Las cajas de diálogo presentan opciones para escoger en forma de controles simples de todo tipo y también de listas, y tienen al menos un botón para confirmar y a menudo botones de ayuda
© Editorial UOC
228
Ingeniería del software
y de cancelación. Generalmente, van solas dentro de una ventana modal. Usos típicos de las cajas de diálogo son la elección de opciones de impresión, la apertura de ficheros y la presentación de mensajes que exigen respuesta, o al menos confirmación, que ya se han visto.
d) Formularios. Son plantillas para la introducción de datos. Se pueden considerar cajas de diálogo en las cuales predominan los campos de texto por encima de los controles para la selección de opciones.
© Editorial UOC
229
Capítulo VI. Diseño orientado a objetos
e) Carpetas. Carpetas de ficheros, y también carpetas con separadores a cada uno de los cuales corresponde una caja de diálogo.
f) Barras de herramientas. Son grupos de botones de mando, que a veces el usuario puede personalizar, de manera que es posible poner sólo los botones deseados. Las barras de herramientas se pueden ocultar o hacer cambiar de forma, de más alargada a más cuadrada, y viceversa. A veces son flotantes y tienen ventana propia, que permanece en primer término aunque no tenga el foco.
© Editorial UOC
230
Ingeniería del software
Los menús
Un menú es una lista de etiquetas (que denominamos opciones del menú) dentro de la cual el usuario puede seleccionar una cada vez haciendo clic con el ratón. Ejemplos de opciones de menú Las opciones del menú pueden representar funciones de una aplicación, ficheros de una carpeta, ordenadores de una red, valores de una variable, etc.
Las opciones del menú pueden ser palabras o frases cortas o iconos y pueden tener significados muy variados. Es posible que haya opciones las cuales en un momento dado no sean seleccionables, y entonces aparecen en gris en lugar de en negro. Además de las opciones, puede haber líneas de separación de grupos de opciones. Cada opción puede ir acompañada de un acelerador (combinación de teclas equivalente a la opción), un mnemotécnico (una letra equivalente a la opción) y una marca que indica que se ha seleccionado la opción. Clasificación de los menús
a) Menús permanentes. Son aquellos menús que están asociados a una ventana de aplicación y son visibles mientras la ventana permanece activa. Los más habituales son los menús de barra.
© Editorial UOC
231
Capítulo VI. Diseño orientado a objetos
b) Menús temporales. Estos menús son visibles sólo cuando el usuario los abre*, y desaparecen cuando el usuario selecciona un elemento, o bien cuando suelta el botón del ratón (en algunos casos), o hace clic en otro objeto.
Además de las opciones, puede haber líneas de separación de grupos de opciones. Cada opción puede ir acompañada de un acelerador (combinación de teclas equivalente a la opción), un mnemotécnico (una letra equivalente a la opción) y una marca que indica que se ha seleccionado la opción. c) Menús desplegables. Los denominados menús desplegables o menús de persiana (en inglés, pull_down, drop down menus) se despliegan hacia abajo.
* . Un menú se abre por ejemplo, seleccionando un elemento del menú de barra o de otro menú temporal, o bien haciendo clic en un icono.
© Editorial UOC
232
Ingeniería del software
d) En los sistemas de menús en cascada, cuando se selecciona un elemento de un menú desplegable, se despliega otro menú al lado. Un elemento de un menú al cual le corresponde un nuevo menú acostumbra a ir acompañado de un triángulo negro con la punta hacia el lado donde está dicho menú.
e) Menús emergentes. Estos menús (en inglés, pop_up menus) no forman parte de una cascada, sino que surgen (a menudo hacia arriba o hacia la dirección en que hay más espacio disponible) cuando el usuario hace clic con el ratón dentro de un área determinada de una ventana o del escritorio. Entre estos tipos de menús están los asociados a un objeto gráfico, que a menudo se despliegan con el botón derecho.
© Editorial UOC
233
Capítulo VI. Diseño orientado a objetos
7.1.2. La interacción
En este subapartado pasamos a mencionar los diferentes tipos de interacción que podemos encontrar y la manera en que se resuelven. El modelo objeto-acción Para describir la interacción entre el usuario y el ordenador mediante una interfaz gráfica utilizaremos el modelo objeto-acción. El modelo objeto-acción considera que una interacción elemental tiene dos fases: • Primero, el usuario selecciona un objeto. • Después, el usuario selecciona una acción que se aplicará sobre este objeto. A veces intervienen dos objetos: aquél con el cual el usuario trabaja y aquél al cual transfiere información. Por ejemplo, cuando un fichero se mueve en una carpeta.
La selección de objetos
La selección de objetos consiste en la identificación por el usuario de un objeto o más de cara a hacer después una acción o más sobre éstos, pero no sobre el resto de los objetos. La selección se realiza principalmente haciendo clic en los objetos con el ratón, pero también se puede llevar a cabo con el cursor si se utilizan las teclas que lo mueven. Los objetos seleccionados cambian de aspecto. La selección puede ser de dos tipos: 1) Selección simple. Se selecciona un único elemento de una lista (un icono o un carácter de un texto). 2) Selección múltiple. Los otros casos de selección, incluida la selección total de un documento, lista, tabla o diagrama. En la selección múltiple de los objetos de una lista o de caracteres de un texto, ésta puede ser contigua o no.
© Editorial UOC
234
Ingeniería del software
La activación
Ejemplos de activación de objetos Para activar un botón, se le invoca mediante la selección y a la vez se pone en marcha una acción vinculada al mismo. Para activar una ventana, hay que hacer clic sobre la misma en cualquier lugar. Entonces la ventana pasa a primer término, aparecen los controles de redimensionamiento y su marco toma color, mientras que la ventana que antes era activa pierde los controles, su marco se vuelve gris y queda en segundo término. La activación de menús emergentes se hace a menudo con el botón derecho del ratón.
Transferencia de datos
La transferencia de datos consiste en mover objetos de un objeto contenedor (objeto fuente) a otro (objeto de destino). Las modalidades generales de transferencia de datos que podemos encontrar son:
• Arrastrar y dejar (en inglés, draf and drop), por manipulación directa. • Cortar / copiar y pegar (en inglés, cut/copy and paste) mediante el portapapeles, por manipulación indirecta. La retroalimentación
La finalidad de la retroalimentación (en inglés, feedback) es que el usuario vea inmediatamente el efecto de sus acciones, incluso cuando todavía no se han completado.
Ejemplos de modalidades de retroalimentación Hay muchas modalidades de retroalimentación. A continuación mencionamos algunas: • Los cambios de la forma del cursor cuando se sitúa en diferentes partes de una ventana. • Los cambios de color de los objetos seleccionados.
© Editorial UOC
235
Capítulo VI. Diseño orientado a objetos
• La silueta del objeto fuente que sigue el cursor durante una operación de arrastre, mientras que el objeto de destino cambia de color cuando se entra en él. • Los indicadores de progreso de operaciones largas, en forma de barras vacías (graduadas o no) que se van llenando, o de porcentajes que se van actualizando, o de mensajes.
Estilos de interacción
La interacción con la interfaz de usuario se puede llevar a cabo mediante menús, formularios, pregunta-respuesta, que puede ser lineal (siempre la misma serie de preguntas) o jerárquica (cada pregunta depende de las respuestas anteriores); lenguaje de mandatos, teclas de función, que pueden ser dedicadas (siempre la misma función) o programables; manipulación directa o lenguaje natural. Manipulación directa e indirecta
La manipulación de los objetos por el usuario puede tener lugar de una manera más concreta o más abstracta, según una gama de posibilidades bastante amplia. Los extremos de esta gama son los siguientes estilos genéricos: a) Manipulación directa, en la cual el usuario indica al sistema la acción que quiere llevar a cabo sobre el objeto seleccionado simulándola con el ratón, estirando el objeto, arrastrándolo, etc. b) Manipulación indirecta, en la cual, una vez seleccionado el objeto, el usuario indica al sistema la acción que quiere llevar a cabo sobre el objeto de una manera abstracta. Las ventajas de la manipulación directa son las siguientes: Definición de abstracto y concreto La definición de qué es concreto y qué es abstracto depende del usuario, puesto que para un matemático el hecho de operar con ecuaciones se podría entender como una manipulación directa.
• La manipulación directa hace el aprendizaje mucho más fácil. • El usuario recuerda mejor el uso del producto. • El usuario tiene la sensación de que controla más lo que pasa. • El usuario ve de manera inmediata el resultado de sus acciones.
© Editorial UOC
236
Ingeniería del software
Por otro lado, la manipulación directa presenta los siguientes inconvenientes: • A menudo ocupa mucho espacio en la pantalla. • A veces, su uso es más lento. • No siempre es fácil encontrar un modelo adecuado. Ayuda en línea al usuario
La ayuda en línea (en inglés, on_line) al usuario es una alternativa a los tradicionales manuales impresos, que tiene importantes ventajas en comparación con éstos: • No ocupa lugar en estanterías ni en la mesa de trabajo. • No tiene deterioro físico. • Es más fácil y barato ponerla al día. • Se presta al aprendizaje interactivo (tutoriales on-line). • El usuario puede recurrir a la información que busca de una manera más rápida y flexible. • No tiene una estructura lineal, sino en red (hipertexto). Ahora bien, también presenta algunos inconvenientes y limitaciones, que mencionamos a continuación: • Generalmente, es un poco más difícil leer de una pantalla que de un manual. • El paso entre páginas consecutivas es más lento (en cambio, el salto a una página referenciada es mucho más rápido). • No se pueden hacer anotaciones al margen (pero hay sistemas que permiten que el usuario añada anotaciones propias en los textos de ayuda). • La ayuda presentada tapa temporalmente la ventana donde trabajaba el usuario, al menos en parte.
7.2. El diseño de las interfaces gráficas En primer lugar, veremos algunas características que conviene que tengan las interfaces, después estudiaremos el proceso del diseño y, finalmente, haremos algunas recomendaciones sobre el uso de los distintos elementos gráficos.
© Editorial UOC
237
Capítulo VI. Diseño orientado a objetos
7.2.1. Características de un buen diseño
El diseño debe tender a conseguir el mejor compromiso, para un software concreto, entre las siguientes características: a) Sensación de control. Los usuarios no quieren tener la sensación de ser controlados por el ordenador, e incluso en el caso de tutoriales guiados conviene dejar que el usuario tome la iniciativa de vez en cuando; es preciso que la interfaz sea esencialmente pasiva y la ayuda en línea, discreta. b) Adecuación al usuario. Los usuarios no son iguales que el diseñador (no son profesionales de las GUI) y tampoco son iguales entre ellos. c) Familiaridad para el usuario. Conviene utilizar los conceptos, terminología y organización a los que el usuario está acostumbrado. d) Adecuación a la tarea del usuario. La interfaz gráfica de usuario debe integrarse en el flujo de trabajo del usuario. e) Adecuación al flujo de operaciones. Hay casos en los cuales el usuario cambia de tarea de manera frecuente e imprevisible. En estas situaciones, el cambio de tarea informática debe ser ágil. En cambio, en ocasiones el usuario cambia de una tarea determinada a otra, que es siempre la misma; entonces conviene que el sistema pase directamente. f) Continuidad con las versiones anteriores del software. Aunque un software nuevo siempre se hace para mejorar, conviene no obstante aprovechar al máximo la experiencia del usuario con las versiones anteriores, y presentarle lo mismo de igual manera, si no hay una razón de peso para hacerlo de un modo distinto. g) Manipulación directa. Generalmente será mejor para el usuario. Ahora bien, la manipulación directa no siempre es viable. h) Flexibilidad. Conviene que la interfaz sea adaptable a las preferencias del usuario, y también a su nivel de experiencia. i) Tiempo de respuesta adecuado. El usuario espera que el ordenador responda rápido, pero, sobre todo, que cada vez que realiza la misma operación tarde más o menos el mismo tiempo. Cuando se prevé que una operación puede ser larga, conviene sacar un mensaje para tranquilizar al usuario que diga que la operación va bien, o bien mostrarle el avance del proceso por medio de una barra que va cambiando de color por partes o un porcentaje de cumplimiento de la tarea.
© Editorial UOC
238
Ingeniería del software
j) Atención a la posibilidad de errores de usuario. k) Feedback inmediato al usuario. Por un lado, el usuario debe poder darse cuenta de que su acción ha sido aceptada o rechazada o de si ya se ha completado o no. Por otro lado, cuando la acción se ha completado, el usuario tiene que ver el resultado claramente (punteros y cursores situados de modo inmediato, siluetas que siguen el arrastre de objetos), etc. l) Sensación de seguridad del usuario. Se debe facilitar que el usuario explore el producto sin riesgo de perder información o de perderse, permitiéndole deshacer la última acción y pidiendo confirmación de las acciones peligrosas. m)Robustez. El ideal de robustez es que, haga lo que haga el usuario, el software no se descontrole. n) Coherencia. Es necesario que los elementos que desempeñan el mismo tipo de función tengan el mismo aspecto: títulos, nombres de campos. Es deseable que haya consistencia tanto dentro de una aplicación como entre aplicaciones, ya que en ambos casos puede facilitar extraordinariamente el aprendizaje. En el caso de interfaces implementadas con una herramienta orientada a objetos, el uso sistemático de la herencia facilita el mantenimiento de la coherencia. Ejemplo de coherencia Conviene que los botones en pantallas diferentes que sirven para la misma función sean iguales en cuanto a forma, medidas, color, texto y, si procede, posición.
o) Facilidad de utilización. p) Facilidad de aprendizaje. A menudo, es difícil hacer compatibles todas estas características.
7.2.2. Método de diseño de las interfaces gráficas
Consideraremos un método con las siguientes etapas: elaboración de una guía de estilo, diseño y evaluación del diseño en cuanto a las características de
© Editorial UOC
239
Capítulo VI. Diseño orientado a objetos
buen diseño mencionadas y al cumplimiento de la normativa y recomendaciones de estilo. 1) Elaboración de una guía de estilo La guía de estilo debe incluir una normativa sobre todos los aspectos de la interfaz que conviene que estén normalizados: • Ventanas de aplicación, de documento y de cajas de diálogo: estilo, colores y controles. • Tipo de letra e iconos estándar. • Controles estándar, como botones de confirmación, cancelación y ayuda. • Feedback: formas del puntero y del cursor y uso de cada una, etc. • Si la herramienta de interfaz gráfica está orientada a objetos, definir las superclases básicas, de las cuales se definirán subclases en la etapa de implementación.
2) Diseño La etapa de diseño parte del esquema del contenido de las ventanas y de la especificación formal de los casos de uso obtenidos en la etapa de análisis. El esquema del contenido sólo indica qué datos deben figurar en cada ventana y cuáles de éstos tienen una lista de valores posibles limitada, y aquellos aspectos que deban ser comunes a todas las ventanas de un mismo tipo estarán fijados por la guía de estilo. A partir de esta información se debe determinar la mejor manera de representar cada dato con la herramienta de interfaces gráficas disponible y después establecer el formato de cada ventana, ya sea mediante la herramienta con que se implementará la interfaz de usuario definitivamente, ya sea haciendo alguna clase de prototipo que después se tendrá que implementar de manera fiel. Teniendo en cuenta el diálogo* descrito dentro de la especificación formal de los casos de uso, se diseñará el instrumento para seleccionar la función (menús, barras de herramientas, etc.) y también los controles que servirán para pasar de *. El diálogo es el intercambio de mensajes entre el software y el usuario.
© Editorial UOC
240
Ingeniería del software
una ventana a otra. Habrá que buscar unos iconos adecuados; para asegurarse de que lo son, se comprobará si los usuarios los reconocen fácilmente.
7.2.3. Recomendaciones sobre el diseño de objetos gráficos
Aquí veremos algunas recomendaciones relativas a ventanas, menús, controles y cajas de diálogo y también algunas orientaciones sobre la ayuda en línea.
Recomendaciones sobre ventanas
a) Cuando se abra una ventana, conviene situarla en primer lugar, darle el foco y mantener una lista seleccionable de ventanas abiertas. Si es necesario, conviene ponerle controles de maximizar y minimizar. b) Cuando se reabra una ventana, es recomendable que se haga en la misma posición y con las mismas medidas. c) Es conveniente prever algún control para cerrar las ventanas de aplicación y de documento, cerrando o no la aplicación o documento respectivos. d) No se tiene que permitir que la ventana se pueda mover a una posición en la que sea inaccesible, y conviene hacer saber al usuario que se está a punto de mover la ventana o de redimensionarla (puntero con una forma especial) y el movimiento en curso. e) Cuando se maximiza una ventana, hay que guardar sus dimensiones anteriores y poner el control de minimizar o restaurar. f) Cuando se minimiza una ventana por primera vez, se tiene que colocar el icono en la parte baja del escritorio. Si la ventana ya se había minimizado, se debe poner el icono en el lugar en que estaba antes.
Recomendaciones sobre menús
a) Hay que presentar de manera diferente del resto la opción que se selecciona y las que están inhabilitadas. En el caso de opciones binarias, conviene
© Editorial UOC
241
Capítulo VI. Diseño orientado a objetos
indicar cuáles están seleccionadas, o cambiar el texto según estén seleccionadas o no. b) Las opciones que se prevé que se utilizarán más deben ir al comienzo del menú. c) Conviene evitar un número de niveles excesivo en los menús en cascada. d) Los menús pop-up tienen que ser de un solo nivel y no repetir las opciones de los menús ordinarios. Recomendaciones sobre controles
a) La lista combo se utilizará cuando un campo pueda tomar unos valores muy frecuentes (que serán los de la lista), pero, no obstante, pueda tomar otros, que debe ser posible teclear. b) La lista ordinaria es adecuada cuando la lista de valores posibles está cerrada y es reducida. No obstante, si hay pocos valores posibles, se debe considerar la alternativa mucho más rápida de los botones de radio, si los valores son excluyentes entre ellos, o las check boxes en el caso contrario. c) Tanto la lista ordinaria como la lista combo se harán desplegables cuando haya problemas de espacio, y persistentes con barra de desplazamiento cuando se disponga de espacio, pero la lista tenga demasiados valores. Los valores de la lista tienen que ir ordenados por frecuencia de uso decreciente o por orden alfabético, etc. d) Una spin box es conveniente principalmente cuando los valores sugeridos son numéricos con intervalos iguales. Se puede admitir o no un valor tecleado directamente. e) Los campos de texto de una sola línea pueden tener visible sólo la parte donde está el cursor. Los campos de líneas múltiples pueden tener barra de desplazamiento vertical y horizontal, y puede ser necesario permitir los saltos de línea con una tecla que ya no se podrá dedicar a otro uso en la misma ventana. Recomendaciones sobre cajas de diálogo
a) Una caja de diálogo modal es adecuada cuando hay que interrumpir el proceso para advertir al usuario de una circunstancia anómala o pedirle una
© Editorial UOC
242
Ingeniería del software
confirmación de una acción conflictiva que haya pedido. Tiene que aparecer en primer término y recibir el foco. No se tiene que recurrir casi nunca a las cajas de diálogo modales, ya que hacen perder tiempo al usuario. b) Si la caja de diálogo puede tapar información que el usuario puede necesitar para tomar la decisión que se le pide, es necesario que sea posible desplazarla por la pantalla. c) Las cajas de diálogo no tienen que llenar toda la pantalla. Pueden tener doble formato: primero se presenta una caja de diálogo con los controles imprescindibles, y se da opción al usuario de desplegar el resto. d) En una caja de diálogo debe haber al menos un botón para cerrarla. A menudo hay dos, uno para confirmar y otro para cancelar, que se recomienda que estén separados de los eventuales botones de mando. Se aconseja que los botones estén alineados horizontalmente (en la parte de abajo, hacia el ángulo derecho) o bien verticalmente. Conviene que haya un botón por omisión (es decir, el botón que se selecciona con la tecla de retorno de carro) con el contorno más grueso que los otros botones y colocado en la parte superior de una columna de botones o en el extremo de una fila. El botón de ayuda también debe estar en una posición destacada. e) Si hay un número significativo de controles, se deben distribuir en grupos. Los controles de un grupo deben estar relacionados lógicamente, pero no hace falta que sean del mismo tipo. Los grupos tienen que estar rodeados por alguna línea o bien deben tener un texto de cabecera del grupo y sus campos tienen que estar alineados entre sí y sangrados respecto al texto de cabecera. Si hay varios grupos, los textos de cabecera respectivos tienen que estar alineados. En un mismo grupo de controles puede haber campos de texto y grupos de botones de radio.
f) Las carpetas con separadores son convenientes cuando la cantidad de información que se presenta es tan grande que puede llenar varias veces la ventana de la caja de diálogo. Principios del diseño de la ayuda en línea
A continuación, mencionamos algunos principios que se deben tener en cuenta a la hora de realizar el diseño de la ayuda en línea:
© Editorial UOC
243
Capítulo VI. Diseño orientado a objetos
1) El acceso a la ayuda tiene que ser fácil de encontrar. 2) La redacción de los textos se tiene que hacer poniéndose en el lugar del usuario, igual que en el caso de los manuales. 3) La información tiene que ser tan completa como sea posible, pero debe estar estructurada de manera que resulte fácil localizar exactamente lo que el usuario quiere en cada momento. 4) Debe ser posible volver a los textos de ayuda ya vistos en la misma sesión de ayuda. 5) Debe ser posible salir fácilmente de la ayuda y volver al punto en el que el usuario había interrumpido su trabajo. 6) El tiempo de respuesta tiene que ser breve, ya que a menudo el usuario no encuentra lo que buscaba en el primer intento. 7) Debe tener un formato y un estilo coherentes tanto con el resto de la interfaz como con el resto de la documentación.
8. Diseño de los subsistemas
Al comenzar el diseño, dentro del diseño arquitectónico, se había establecido una descomposición del sistema de software en subsistemas y se habían especificado las interfaces respectivas y las dependencias entre éstas. Todo esto era provisional porque no se conocían todavía todas las clases del diagrama estático del diseño. Cuando se acaba el diseño, conviene llenar de contenido los subsistemas mencionados especificando qué clases comprende cada uno, haciendo explícitas las dependencias en el nivel de clase y de operación entre sí y comprobando si entre todas las clases y subsistemas de cada subsistema se implementa la interfaz explícita o implícita de la cual es responsable el subsistema. Si hay interfaces definidas explícitamente, conviene que las dependencias queden especificadas no entre subsistemas sino entre un subsistema y una interfaz, para facilitar la sustitución de un subsistema por otro que implemente la misma interfaz.
© Editorial UOC
244
Ingeniería del software
9. Ejemplo
En este apartado continuamos el ejemplo de los capítulos anteriores. Veamos ahora el diseño. En situaciones reales, las especificaciones del diseño utilizarían la terminología propia del lenguaje de programación, la herramienta de interfaz gráfica y el sistema de gestión de bases de datos concretos que se tengan que utilizar en la implementación, pero al tratarse de un ejemplo general se ha utilizado una terminología neutra.
9.1. El diseño arquitectónico
Puesto que no se utilizarán subsistemas ya existentes ni tampoco se prevé que ningún subsistema sea reutilizable, los subsistemas corresponden a los paquetes identificados en el análisis.
9.2. El diseño de los casos de uso
Caso de uso 1: ‘Añadir local’
Cuando el usuario selecciona la opción correspondiente al menú, se llama la operación crear de la clase AdicionLocal. Esta operación instancia la clase, determina el valor del número correlativo del local, abre una ventana e instancia el formato de pantalla PAñadirLocal.
Otro procedimiento En lugar de especificaciones textuales (sangradas para indicar qué condiciones están subordinadas a otras) se podrían realizar diagramas de secuencia, pero en los casos reales a menudo serían muy complejos.
© Editorial UOC
245
Capítulo VI. Diseño orientado a objetos
1) Si el usuario cancela, se llama la operación borrar de la clase AdicionLocal y se devuelve control al menú. 2) Si el usuario confirma, se llama la operación buscar de la clase Propietario con el NIF del propietario como parámetro. Entonces esta clase llama materializar de GestorCliente con el mismo parámetro.
a) Si no se encuentra al propietario, se llama la operación crear de la clase AdicionPropietario descrita en el caso de uso 2. b) Si está el propietario o se ha añadido, se llama la operación crear de la clase TiendaAlmacen, Oficina, Inmueble o Polivalente y se le pasa como parámetros la zona, el tipo, el número, la dirección del local, la superficie, el NIF del propietario, las características, las restricciones y el agente y el volumen en el caso de tiendaalmacén y polivalente, y las características polivalentes en el caso de polivalente. Esta operación crea un objeto de la subclase correspondiente, mueve estos valores uno a uno a sus atributos y llama grabar de GestorLocal con el objeto creado como parámetro.
Caso de uso 2: ‘Añadir propietario’
Cuando el usuario selecciona la opción correspondiente al menú, se llama la operación crear de la clase AdicionPropietario y ésta abre una ventana modal para introducir el NIF.
1) Si el usuario cancela, se llama la operación borrar de la clase AdicionPropietario y se devuelve el control al menú. 2) Si el usuario confirma, se llama la operación buscar de la clase Propietario con el NIF del propietario como parámetro y entonces la clase llama materializar de GestorCliente con el mismo parámetro.
a) Si se encuentra el propietario, se abre una ventana modal y se muestra el mensaje “El propietario con NIF X ya existe”. b) Si no se encuentra el propietario, se abre una ventana y se presenta el formato de pantalla PAñadirPropietario.
© Editorial UOC
246
Ingeniería del software
• Si el usuario cancela, se llama la operación borrar de la clase AdicionPropietario y se devuelve el control al menú. • Si el usuario confirma, se llama la operación crear de la clase Propietario y se le pasan como parámetros el NIF, los apellidos y nombre/razón social, la dirección y el teléfono. La crea el objeto, le pone los valores de los atributos y llama grabar de GestorClientes con el objeto como parámetro. Caso de uso 3: ‘Introducir informe’
Cuando el usuario selecciona la opción correspondiente al menú, se llama la operación crear de la clase IntroduccionInforme. Esta operación instancia la clase y abre una ventana modal que pide el código del local.
1) Si el usuario cancela, se llama la operación borrar de la clase IntroduccionInforme y se devuelve control al menú. 2) Si el usuario confirma, se llama la operación buscar de la clase Local con los componentes del código del local (zona, tipo y número) como parámetros. Ésta llamará materializar de GestorLocal. a) Si no se encuentra el local, se muestra el mensaje “El local XXX no existe” en una ventana modal, se llama la operación borrar de la clase IntroduccionInforme y se devuelve el control al menú. b) De otra manera, se abre una ventana y se presenta el formato de pantalla PIntroducirInforme. • Si el usuario introduce los datos y confirma, se llama la operación modificar de la clase Local y se le pasan como parámetros los mismos que para la operación crear más un valor nulo para el NIF del arrendatario, la forma, la accesibilidad, las instalaciones, la visibilidad, la conservación, el precio y el inspector. Esta operación sustituye los valores de los atributos por los valores tecleados, llama grabar de GestorLocal y le pasa el objeto de Local como parámetro. • Si el usuario cancela, se llama la operación borrar de la clase AdicionPropietario y se devuelve el control al menú.
© Editorial UOC
247
Capítulo VI. Diseño orientado a objetos
Caso de uso 4: ‘Introducir contrato’
Cuando el usuario selecciona la opción correspondiente al menú, se llama la operación crear de la clase IntroduccionContrato. La operación instancia la clase, abre una ventana y presenta el formato de pantalla PIntroducirContrato. 1) Si el usuario cancela, se llama la operación borrar de la clase IntroduccionContrato y se devuelve control al menú. 2) Si el usuario confirma, se llama la operación buscar de la clase Local con la zona, el tipo y el número como parámetros.
a) Si no se encuentra el local, se muestra el mensaje “El local XXX no existe”, se llama la operación borrar de la clase IntroduccionContrato y se devuelve el control al menú. De otro modo, se llama la operación buscar de la clase Arrendatario con el NIF como parámetro. b) Si no se encuentra el arrendatario, se llama la operación crear de la clase AdicionArrendatario, que abre una ventana y presenta el formato de pantalla PIntroducirArrendatario.
• Si el usuario cancela, se llama la operación borrar de la clase IntroduccionContrato y se devuelve el control al menú. • Si el usuario confirma, se llama la operación crear de la clase Arrendatario y se le pasan como parámetros el NIF, los apellidos y nombre/razón social, la dirección y el teléfono. Entonces la clase llamará grabar de GestorCliente con los mismos parámetros.
Después se llama la operación crear de la clase Contrato y se le pasa como parámetros el NIF del arrendatario y el NIF del propietario, el código del local, la fecha de inicio y la de finalización. Esta operación crea un objeto Contratos, le pone los valores de los atributos y llama estas otras: buscar de Propietario y de Arrendatario con los NIF respectivos como parámetros, buscar de Local con la zona, el tipo y el número como parámetros, modificar de Local con los datos leídos más el NIF del arrendatario y grabar de GestorContrato, e imprime los datos del contrato: NIF, apellidos y nombre/razón social y dirección tanto del propietario
© Editorial UOC
248
Ingeniería del software
como del arrendatario, la dirección del local, la fecha de inicio y la de finalización.
Caso de uso 5: ‘Añadir arrendatario’
Cuando el usuario selecciona la opción correspondiente al menú, se llama la operación crear de la clase AdicionArrendatario. Ésta abre una ventana modal para introducir el NIF. 1) Si el usuario cancela, se llama la operación borrar de la clase AdicionArrendatario y se devuelve el control al menú. 2) Si el usuario confirma, se llama la operación buscar de la clase Arrendatario con el NIF del arrendatario como parámetro.
a) Si se encuentra el arrendatario, se abre una ventana modal y se muestra el mensaje “El arrendatario con NIF ya existe”. b) Si no se encuentra al arrendatario, se llama la operación crear de la clase AdicionArrendatario, que abre una ventana y presenta el formato de pantalla PAñadirArrendatario. • Si el usuario cancela, se llama la operación borrar de la clase AdicionArrendatario y se devuelve control al menú. • Si el usuario confirma, se llama la operación crear de la clase Arrendatario y pasa como parámetros el NIF, los apellidos y nombre/razón social, la dirección, el teléfono. Esta operación crea un objeto Cliente, le pone los valores de los atributos y llama grabar de GestorCliente con el objeto creado como parámetro.
Caso de uso 6: ‘Añadir eventual arrendatario’
Este caso es una especialización del caso de uso número 5 en el cual las clases Arrendatario y AdicionArrendatario se sustituyen por EventualArrendatario y AdicionEventualArrendatario respectivamente. La operación crear de la clase EventualArrendatario tiene como parámetros la lista de zonas, el tipo, la superficie y los requisitos además de los parámetros de crear de Arrendatario.
© Editorial UOC
249
Capítulo VI. Diseño orientado a objetos
Caso de uso 7: ‘Buscar locales’
Cuando el usuario selecciona la opción correspondiente al menú, se llama la operación crear de la clase BuscaLocales. La operación instancia la clase, abre una ventana y presenta el formato de pantalla PBuscarLocales. Casos de uso adicionales De acuerdo con lo que se ha especificado en la etapa de análisis habría que prever casos de uso adicionales para que toda la información se pudiera consultar, modificar y borrar.
1) Si el usuario cancela, se llama la operación borrar de la clase BuscaLocales y se devuelve el control al menú. 2) Si el usuario confirma, se llama la operación consultar de la clase Local con el NIF del propietario y del arrendatario, la zona, el tipo, el número y la superficie mínima como parámetros. Esta operación llama consultar de GestorLocal con los mismos parámetros. En el caso de que el tipo pedido sea tienda-almacén u oficina se buscan también los de tipo polivalente. a) Si no se encuentra ningún local, se abre una ventana modal y se muestra el mensaje “No hay ningún local que cumpla las condiciones”. b) Si se encuentra al menos un local, se abre una ventana y se presenta el formato de pantalla PListaLocales. • Si el usuario selecciona un local de la lista y confirma, se llama la operación buscar de la clase Local y se le pasan como parámetros la zona, el tipo y el número del local seleccionado; después, se abre una ventana y se presenta el formato de pantalla PDatosLocal. Cuando el usuario cancela, se vuelve a sacar el formato de pantalla PListaLocales. • Si el usuario cancela, se llama la operación borrar de la clase BuscaLocales y se devuelve el control al menú.
9.3. El diagrama estático de diseño En las clases del diagrama estático de diseño se han indicado sólo los atributos que se han añadido a la versión de análisis para implementar las asociaciones; las operaciones se indican todas.
© Editorial UOC
250
Ingeniería del software
© Editorial UOC
251
Capítulo VI. Diseño orientado a objetos
En Local se han incluido el NIF del propietario y el del arrendatario para implementar las asociaciones de esta clase con Propietario y arrendatario respectivamente; sólo se ha implementado uno de los sentidos de estas asociaciones, ya que no es necesaria la navegabilidad en sentido contrario. En Contrato se han añadido el NIF del arrendatario y la zona, tipo y número del local para implementar las asociaciones correspondientes. La herencia doble de Polivalente se ha convertido en herencia simple de TiendaAlmacen sin tener que hacer nada más, ya que no hereda ni atributos ni operaciones de Oficina. Sólo se especifica la lista de parámetros de las operaciones cuando es corta, por razones de espacio y porque ya están descritas completamente en la especificación de los casos de uso. Sin embargo, cuando se documentan las clases con herramientas CASE, que a menudo permiten visualizar las listas de parámetros de varias maneras, sí que se especifican completamente. Sólo se han incluido las operaciones que figuran en el diseño de los casos de uso. Todas las clases deben tener una operación para borrar los objetos y es conveniente que todas las clases de entidades tengan al menos una operación para modificar los atributos. Naturalmente, tendría que haber también casos de uso que las utilizasen.
9.4. El diseño de la persistencia
Para realizar el diseño de la persistencia en este ejemplo, consideraremos que se utiliza una base de datos relacional.
9.4.1. Diseño de la base de datos
Para hacer el diseño de la base de datos, primero eliminaremos la herencia, después elaboraremos el diagrama ER equivalente al diagrama estático de las clases persistentes y, por último, obtendremos la especificación de la base de datos relacional.
© Editorial UOC
252
Ingeniería del software
Supresión de la herencia
Existen dos jerarquías de herencia encabezadas por las clases Local y Cliente, respectivamente. Entre las opciones mencionadas para la supresión de la herencia (una tabla diferente para cada subclase, una tabla para la superclase y otra para cada subclase, y una sola tabla para todo), hacemos la elección siguiente: 1) Para la jerarquía de Local, la tercera, ya que se supone que las tiendas-almacén serán la mayoría de los locales y el atributo caracteristicas_polivalentes es de longitud variable y, por tanto, su valor nulo ocupa muy poco espacio. 2) Para la jerarquía de Cliente, la segunda, ya que sólo hay que prever una tabla complementaria para una de las subclases, EventualArrendatario, y ésta es minoritaria, dado que un eventual arrendatario, o bien pasa a arrendatario (y entonces se borran los atributos de la subclase) o bien se borra completamente al poco tiempo. Diagrama entidad-relación
El diagrama entidad relación que corresponde a este caso es el que vemos a continuación:
© Editorial UOC
253
Capítulo VI. Diseño orientado a objetos
Base de datos relacional
En los casos reales, la descripción de la base de datos se hace en términos de un sistema de gestión de bases de datos concreto, obviamente el que se utilizará en el proyecto. Sin embargo, aquí, para que el ejemplo sea más general, se utiliza la terminología general del modelo relacional. Las tablas de la base de datos serán éstas: • tabla_clientes, con las columnas NIF, nombre, direccion y telefono. La clave primaria es NIF. • tabla_eventuales_arrendatarios, con las columnas NIF, tipo_local, zona1, ..., zona5, superficie_minima y requisitos_varios. NIF es la clave primaria y a la vez clave secundaria correspondiente a NIF de tabla_clientes. • tabla_locales, con las columnas zona, tipo, numero, direccion, superficie, caracteristicas, NIF_propietario, accesibilidad, instalaciones, agente, inspector, volumen y caracteristicas_polivalente. La clave primaria se compone de los atributos zona, tipo y numero y NIF_propietario es clave secundaria correspondiente a NIF de tabla_clientes. • tabla_contratos, con las columnas zona, tipo, numero, NIF_arrendatario, fecha_inicio, fecha_fin y vendedor. La clave primaria se compone de los atributos zona, tipo, numero, NIF_arrendatario y fecha_inicio. Hay dos claves secundarias NIF_arrendatario correspondientes a NIF de tabla_clientes, y otra compuesta de los atributos zona, tipo y numero que corresponde a la clave primaria de tabla_locales. En lo que respecta a los índices, debería haber uno por cada clave primaria. En principio, no hace falta índice para ninguna de las claves secundarias.
9.4.2. Gestores de disco Aplicaremos a este caso el esquema general que seguimos en este capítulo. Los gestores son GestorLocal, GestorCliente y GestorContrato, y son subclases de GestorRelacional: a) GestorLocal se instancia al poner en marcha el sistema, por medio de la operación crear. La operación leerFila lee una fila de tabla_locales identificada
© Editorial UOC
254
Ingeniería del software
por la clave primaria con los valores de todas las columnas. La operación filaAObjeto crea un objeto de Local y mueve estos valores uno a uno a sus atributos. La operación objetoAFila mueve uno a uno los atributos del objeto de Local a los valores de las columnas de una fila de tabla_locales. La operación grabarFila graba esta fila en tabla_locales. La operación consultar hace una consulta en tabla_locales con una condición que dependerá de cuáles de los parámetros tengan un valor no nulo y llama filaAObjeto para cada una de las filas obtenidas. b) GestorCliente se instancia al poner en marcha el sistema por medio de la operación crear. La operación leerFila lee una fila de tabla_clientes y otra de tabla_eventuales_arrendatarios identificadas por la clave primaria, y la operación filaAObjeto crea un objeto de EventualArrendatario, si alguno de los atributos específicos de esta subclase tiene un valor no nulo, o un objeto de Cliente y le mueve los valores de las filas mencionadas. La operación objetoAFila mueve uno a uno los atributos del objeto de Cliente a los valores de las columnas de una fila de tabla_clientes y otra de tabla_eventuales_arrendatarios. La operación grabarFila graba la primera de estas filas siempre y la segunda sólo si alguno de los atributos específicos de EventualArrendatario tiene un valor no nulo. c) GestorContrato se instancia al poner en marcha el sistema por medio de la operación crear. La operación leerFila lee una fila de tabla_contratos identificada por la clave primaria con los valores de todas las columnas y la operación filaAObjeto crea un objeto de Local y mueve estos valores uno a uno a sus atributos. La operación objetoAFila mueve uno a uno los atributos del objeto de Contrato a los valores de las columnas de una fila de tabla_contratos. La operación grabarFila graba esta fila en tabla_contratos.
9.5. El diseño de la interfaz de usuario
En este subapartado veremos cómo se representan los diferentes datos, cómo se implementan los diálogos y el diseño de algunas ventanas. No estableceremos ninguna guía de estilo concreta, ya que puede variar bastante de una organización a otra.
© Editorial UOC
255
Capítulo VI. Diseño orientado a objetos
9.5.1. Presentación de los datos
Con vistas a conseguir una interfaz de usuario coherente, es necesario que cada dato se presente de la misma manera en todos los formularios en los que sale. Empezaremos por decidir cómo se presentará cada dato:
• Los datos de tipo textual se presentarán en forma de áreas de texto con barra de desplazamiento vertical, ya que permiten textos medianamente largos y son menos incómodas que las que tienen también barra de desplazamiento horizontal. • Los campos de longitud fija se presentarán como campo de texto cuando son sólo de salida. Cuando son también de entrada, si el número de valores posibles es reducido, el valor se escogerá de una lista (una lista combo, si se pueden añadir valores y una lista ordinaria, en caso contrario); en lugar de una lista ordinaria de menos de seis valores fijos se utilizará un conjunto de botones de radio. • Para datos booleanos, utilizaremos check boxes.
Aplicando estas normas, el tipo de local se introducirá mediante botones de radio; la zona, el agente, el inspector y la conservación se seleccionarán de listas ordinarias; el número de local, los NIF, los teléfonos, las superficies, los datos y el precio serán campos de texto, y también lo serán todos los datos anteriores cuando no se puedan modificar; el resto de los datos lo constituirán textos con barra de desplazamiento vertical. No hay ningún dato booleano y, por tanto, las check boxes sólo se usarán para opciones dentro de las ventanas.
9.5.2. Implementación de los diálogos
Veremos en primer lugar la implementación de la selección de la función y después los instrumentos para pasar de una pantalla a otra.
© Editorial UOC
256
Ingeniería del software
Los menús
Las opciones del sistema de menús son las que corresponden a los casos de uso más las opciones de salir del sistema y de llamar la ayuda en línea. Puesto que son pocas y caben en el menú de barra, no es preciso menús desplegables. Tampoco es necesaria una barra de herramientas, ya que sería una duplicación del menú de barra con iconos en lugar de etiquetas. El menú de barra sale en la parte superior de la pantalla inicial y tiene las entradas correspondientes a estas etiquetas, de izquierda a derecha: ‘Salir’, ‘Alta local’, ‘Informe’, ‘Contrato’, ‘Eventual arrendatario’, ‘Locales’, ‘Propietario’, ‘Arrendatario’ y ‘Ayuda’. ‘Salir’ se ha puesto como primera opción y ‘Ayuda’ como última porque es la misma colocación que en el resto del software que utilizan los usuarios. Se ha utilizado la etiqueta ‘Alta local’ en lugar de ‘Local’ porque la última se parece demasiado a otra. Paso de una pantalla a otra
La opción de cancelar la función se pide por medio de un botón con la etiqueta ‘Cancelar’; la llamada en la ayuda en línea se hace con un botón con la etiqueta ‘Ayuda’; para confirmar los datos introducidos, se hace clic en un botón con la etiqueta ‘Confirmar’ y, para salir de una ventana que muestra el resultado de una consulta, hay un botón con la etiqueta ‘Salir’.
9.5.3. Formato de algunas ventanas
En una situación real, las ventanas y su contenido estarían codificadas con la herramienta con que se implementarán finalmente, o bien con una herramienta de prototipos (en este último caso, durante la implementación se codificaría una interfaz con la misma apariencia por medio de la herramienta definitiva). Aquí hay un dibujo esquemático de las ventanas, si tenemos en cuenta que muchos detalles dependerían tanto de las prescripciones de la guía de estilo como de la herramienta. Veremos dos de las ventanas: la del alta de local (PantallaAñadirLocal) y una ventana modal para un mensaje.
© Editorial UOC
257
Capítulo VI. Diseño orientado a objetos
Como se ha dicho anteriormente, el tipo de local se representa mediante un grupo de botones de radio que corresponden a los cuatro valores posibles. Cuando se presenta la ventana, está seleccionado el valor ‘Tienda-Almacén’, que es el más frecuente. Esto tiene la ventaja de que muchas veces el usuario no deberá seleccionar el valor y el inconveniente de que, si tenía que haber seleccionado otro y no lo hace, da un valor erróneo y no ha recibido ningún aviso. Una punta de flecha sola indica una lista desplegable, y un par significa una barra de desplazamiento vertical.
© Editorial UOC
258
Ingeniería del software
No todas las ventanas modales deben tener los tres botones indicados. Por ejemplo, una ventana que simplemente presente un mensaje muy fácil de interpretar sólo debe tener un botón ‘Salir’.
9.6. El diseño de los subsistemas
Como hemos visto, los subsistemas coinciden con los paquetes establecidos en la etapa de análisis. Estos paquetes son los que vemos a continuación:
El contenido de los subsistemas es el siguiente: a) BasicoLocales comprende las clases Local con todas sus subclases y Cliente con su subclase Propietario, y los gestores de disco correspondientes. En lo que respecta a los casos de uso, incluye el 1 ‘Añadir local’ y el 2 ‘Añadir propietario’.
© Editorial UOC
259
Capítulo VI. Diseño orientado a objetos
b) Informes comprende el caso de uso 3 ‘Introducir informe’. c) Contratos comprende las clases Arrendatario y Contrato y los casos de uso 4 (‘Introducir contrato’), y 5 (‘Añadir arrendatario’). d) Consultas contiene la clase EventualArrendatario y los casos de uso 6 (‘Añadir eventual arrendatario’), y 7 (‘Buscar locales’). De la utilización de las clases y sus operaciones en los casos de uso obtenemos que las interfaces (no formalizadas en términos de UML) de estos subsistemas son las siguientes: • Locales. Las operaciones ‘buscar’, ‘modificar’ y ‘consultar’ de la clase Local. • BasicoLocales. Las operaciones ‘buscar’ y ‘modificar’ de la clase Local.
© Editorial UOC
260
Capítulo VI. Diseño orientado a objetos
Conclusiones
En la etapa de diseño se especifica cómo se tiene que implementar el software para que satisfaga las necesidades de información reunidas en la etapa de recogida y documentación de requisitos y formalizadas en la etapa de análisis. La reutilización es un aspecto cada vez más importante de la construcción de software; durante el diseño se toman las decisiones sobre la reutilización. Los marcos, componentes y clases ya están implementados y, por tanto, se pueden incluir directamente dentro del software a la hora de implementarlo, mientras que los patrones sólo son ideas (probadas y documentadas) para resolver problemas de diseño concretos. El primer paso del diseño es el diseño arquitectónico, dentro del cual se deciden dos aspectos que condicionarán de manera decisiva el resto del diseño: la eventual utilización de marcos y la descomposición del software en subsistemas. La parte principal de la etapa es el diseño de la implementación de los casos de uso, que consiste en la especificación de la colaboración entre las clases de control y también entre éstas y las clases de entidad. Así, se obtiene el diagrama estático de análisis que, un vez revisado de cara a conseguir un acoplamiento bajo, coherencia alta y flexibilidad ante los probables cambios futuros, se complementa con la especificación detallada de las clases que contiene, y en especial de sus operaciones. También hay que diseñar la interfaz de usuario y los mecanismos relativos a la persistencia de las clases de entidades.
© Editorial UOC
261
Capítulo VII. Introducción al software...
Capítulo VII
Introducción al software distribuido
Todos sabemos que cada vez son más raros los ordenadores que no forman parte de una red (más bien, tendríamos que decir de la red mundial). A pesar de que cada uno de los ordenadores de una red podría tener un software independiente que se ejecutase sólo de forma local, en muchas aplicaciones es ventajoso que colaboren distintos ordenadores; las modalidades, conceptos y herramientas básicas para esta colaboración es lo que se ve de forma introductoria, ciertamente en este capítulo.
1. Entornos distribuidos y entornos abiertos
Hablamos de entorno distribuido cuando el software de una aplicación se ejecuta repartido entre varios ordenadores de una red; entonces, también decimos que el software en cuestión es distribuido. La utilización de entornos distribuidos es relativamente reciente, y se debe a la sustitución de las plataformas más antiguas de hardware y software básico. Simplificando, se puede decir que la razón decisiva para la evolución hacia los entornos distribuidos es que la misma capacidad de proceso resulta mucho más barata si se consigue con PC que con mainframes o máquinas Unix. La evolución de las plataformas Por un lado, las tarjetas perforadas fueron arrinconadas por los terminales de pantalla, y después las sustituyeron los microordenadores, que al principio las emulaban;
© Editorial UOC
262
Ingeniería del software
por otro lado, los ordenadores medianos (miniordenadores) reemplazaron, en parte, los mainframes, y después las redes locales y los sistemas cliente/servidor han ocupado el lugar de los sistemas con los miniordenadores y mainframes que quedaban.
1.1. Objetivos de los entornos distribuidos
Los entornos distribuidos fueron creados para alcanzar los siguientes objetivos: 1) Portabilidad de aplicaciones y de servicios del sistema, que quiere decir que las dos se pueden ejecutar indistintamente en varios ordenadores. 2) Interoperabilidad, que significa que sus diferentes ordenadores y aplicaciones sean capaces de comunicarse por medio de instrucciones y formatos de datos que todos comprendan. 3) Integración, que significa que los intercambios de información se pueden hacer sin necesidad de intervenciones externas, y también que el funcionamiento del software y la presentación de la información tengan una cierta uniformidad. Por ejemplo, compartiendo directamente la información.
4) Transparencia, en el sentido de que los usuarios puedan leer datos de un ordenador sin saber dónde está (transparencia en la ubicación de los datos), y los procesos se puedan ejecutar indistintamente en varios ordenadores sin que los usuarios sepan en cuál se ejecutan (transparencia en la ejecución). 5) Facilidad de crecimiento del sistema, que tiene dos vertientes: que se pueda añadir con facilidad hardware o software, y que los componentes de este hardware o software se puedan sustituir sin demasiada complicación por otros más avanzados o más potentes. 6) Compartimiento, en el sentido de que las aplicaciones, los recursos y los servicios puedan ser compartidos sin barreras técnicas (otra cosa son las restricciones de acceso intencionadas). 7) Finalmente, también es importante la seguridad, que consiste en el hecho de que los datos de un usuario estén protegidos, en lo que respecta a consulta y actualización, de los demás usuarios y de los agentes externos, así como de evitar que las comunicaciones se espíen.
© Editorial UOC
263
Capítulo VII. Introducción al software...
1.2. Importancia de las normas en los entornos distribuidos
Para que una arquitectura distribuida se pueda considerar bien diseñada, es preciso que tenga potencialmente una vida mucho más larga que los productos con los que está implementada. Para conseguirlo, es necesario que la arquitectura se base en normas ampliamente aceptadas, hecho que constituye una cierta garantía de que durante bastantes años se encontrarán en el mercado productos que las cumplan y que, por lo tanto, se puedan utilizar para renovar y ampliar el sistema y aumentar su capacidad. Es necesario que la estandarización se aplique en los siguientes campos: ordenadores, plataformas de soporte de la interfaz con el usuario, sistemas operativos, protocolos de comunicaciones y sistemas operativos de red.
1.3. Concepto de sistema abierto
Un sistema abierto es un sistema distribuido en el que se intentan conseguir, por lo menos parcialmente, los objetivos de los sistemas distribuidos, y hacer que las interfaces entre sus componentes respeten un conjunto amplio y completo de normas sobre comunicaciones, programación, presentación e interfaces entre aplicaciones y servicios del sistema aceptadas internacionalmente. Las interfaces en los sistemas abiertos Por ejemplo, en un sistema abierto no hace falta que todos los sistemas operativos sean de tipo Unix, ni es necesario prescindir de los sistemas operativos propios de una marca, siempre que todos los utilizados cumplan las normas que posibiliten el grado necesario de comunicación mediante unas interfaces adecuadas (dicho de otro modo: que un sistema sea o no abierto no es cosa de los productos en sí, sino de sus interfaces).
Cuando hablamos de normas en este contexto, queremos decir lo siguiente: • o bien –y de forma preferente– normas ampliamente utilizadas y establecidas por organizaciones independientes,
© Editorial UOC
264
Ingeniería del software
• o bien normas que inicialmente pertenecen a un fabricante, pero que se han convertido en estándares de facto. Por lo tanto, con el fin de conseguir un sistema abierto, sería necesario evitar los siguientes aspectos: • Los productos muy utilizados pero cerrados, en el sentido de que difícilmente pueden compartir datos con otros productos; • y aquellas normas que, por las razones que sean, han sido objeto de escasas implementaciones.
1.3.1. Beneficiarios de los sistemas abiertos Los sistemas abiertos benefician a los siguientes grupos: • Fabricantes de hardware y sistemas operativos: en la medida en que algunos aspectos del producto están fijados por normas y ya no hace falta estudiar sus alternativas, se puede dedicar más esfuerzo a mejorar sus arquitecturas y su funcionalidad. • Fabricantes independientes de software: se benefician de un mercado más amplio a consecuencia de la portabilidad, hecho que evita la necesidad de versiones específicas para cada plataforma. • Empresas usuarias: se benefician de poder conectar sin problemas productos de fabricantes diferentes y de encontrar más productos en el mercado (ya que muchos productos pasan a ser utilizables en muchas plataformas) y con precios más bajos a causa del aumento de la competencia.
2. Entornos cliente/servidores clásicos
Actualmente, el entorno distribuido que se utiliza más es el denominado cliente/servidor.
© Editorial UOC
265
Capítulo VII. Introducción al software...
La idea básica de la arquitectura cliente/servidor es que un programa, el servidor, gestiona un recurso compartido concreto y hace determinadas funciones sólo cuando las pide otro, el cliente, que es quien interactúa con el usuario. Un ejemplo sencillo de entorno cliente/servidor sería tener un sistema de gestión de base de datos activado en un servidor, y que los programas que se ejecutaran en los ordenadores clientes pudiesen emitir instrucciones de SQL para acceder a esta base de datos.
Normalmente, estos dos programas, el servidor y el cliente, están en ordenadores distintos. Los requerimientos de los ordenadores clientes en lo que respecta a velocidad, memoria y capacidad de disco son muy diferentes de los de los servidores; unos y otros pueden ser ordenadores de modelo y marca diferentes y, además, con frecuencia utilizan un sistema operativo diferente.
2.1. Ventajas e inconvenientes de la arquitectura cliente/servidor
Las ventajas de la arquitectura cliente/servidor son las siguientes: a) Permite que la información se procese cerca de donde se ha generado. b) Dado que las funciones del software quedan repartidas entre varias máquinas, es posible utilizar PC o estaciones de trabajo para los clientes, y máquinas UNIX (por ejemplo) para los servidores, todas de un coste mucho menor que los mainframes. c) El crecimiento del hardware puede ser gradual: • Se puede aumentar gradualmente el número de clientes sin que sea necesario cambiar cada vez el servidor. • Se puede sustituir el servidor sin que los clientes se vean afectados. • Se puede aumentar la capacidad de un cliente sin tener que cambiar ni el servidor ni a los otros clientes. • En algunas modalidades, se pueden añadir servidores sin tener que rediseñar la arquitectura en su conjunto.
© Editorial UOC
266
Ingeniería del software
d) Facilita el uso de interfaces gráficas de usuario y aplicaciones multimedia; la razón es que estas funciones necesitan el tratamiento de un volumen importante de información. Este tratamiento, si tuviese que hacerse de forma centralizada, necesitaría un host de gran capacidad y unos envíos de información muy considerables mediante las líneas. Muchas de estas ventajas significan simplemente que se consiguen, en mayor o menor grado, los objetivos de los entornos distribuidos. Los inconvenientes de la arquitectura cliente/servidor son los siguientes: a) El servidor puede ser un cuello de botella. b) El software distribuido es más complejo que el no distribuido, y también es más difícil probarlo y depurar errores en él; también la administración y la problemática de seguridad son bastante más complejas. c) Cualquier sistema distribuido tiende a fallar con más frecuencia que un sistema centralizado, ya que tiene más componentes que pueden fallar independientemente.
2.2. Arquitecturas cliente/servidor de dos capas
Ahora veremos diferentes entornos de arquitecturas cliente/servidor de dos capas: 1) Entornos cliente/servidor de primera generación: es típico de las redes de área local (LAN); los clientes son PC o estaciones de trabajo en los que se ejecutan las aplicaciones; al principio, los servidores sólo llevan a cabo funciones generales y de bajo nivel, como por ejemplo gestionar ficheros o impresoras compartidas. Más adelante se empieza a pasar parte de las aplicaciones a un servidor adicional, si bien los clientes continúan iniciando y controlando los procesos en parte. 2) Entornos de igual a igual: un ordenador actúa como cliente para otras máquinas, y como servidor para estas mismas u otras, incluso para sí mismo.
© Editorial UOC
267
Capítulo VII. Introducción al software...
3) Entornos cliente/servidor de segunda generación: hay varios servidores especializados en funciones diferentes que pueden pedir los clientes; por ejemplo, gestión de bases de datos, aplicaciones, etc. Los clientes pueden ser móviles.
2.2.1. Imitaciones de la arquitectura cliente/servidor de dos capas
Este tipo de arquitecturas presenta las siguientes limitaciones: • Limitaciones al crecimiento del número de clientes, ya que todos se conectan directamente al servidor. • Dificultad de mantener el software de los clientes, ya que cualquier cambio se debe hacer en todos al mismo tiempo.
2.3. Arquitecturas de más de dos capas
2.3.1. Arquitectura de tres capas basada en plataformas
En el caso más general de arquitectura de tres capas basada en plataforma, la estructura es la siguiente: 1) Primera capa: el servidor. 2) Segunda capa: los agentes. 3) Tercera capa: los clientes. Los agentes pueden realizar funciones como por ejemplo éstas: • Traducción de aplicaciones. Ejemplo Una traducción de aplicación consiste, por ejemplo, en adaptar a un entorno cliente/ servidor una aplicación antigua sobre el servidor.
© Editorial UOC
268
Ingeniería del software
• Control de la carga del servidor. • Servicios de agente inteligentes, como por ejemplo descomponer una petición de servicio por parte de un cliente en varias peticiones a uno o a varios servidores; el hecho de que hubiese varios servidores representaría cierta transición hacia el middleware (programa intermedio). Este modelo se puede expandir horizontalmente a todos los niveles con una cierta facilidad. El inconveniente principal es la fuerte dependencia de las plataformas utilizadas.
2.3.2. Arquitectura de tres capas basada en las funciones
Este tipo de arquitectura presenta las tres capas siguientes: 1) Clientes, que tienen la lógica de tratamiento de la interfaz con el usuario y parte de la lógica de aplicación. 2) Servidores de aplicación, en los que reside la mayor parte de la lógica de aplicación y manipulación de datos. 3) Servidores de datos, que presentan los gestores de bases de datos.
3. Entornos con middleware: CORBA
3.1. Concepto de middleware
Cuando la red aumenta todavía más sus dimensiones e incorpora multiplicidad de aplicaciones, plataformas y redes, es necesario un componente que gestione la comunicación entre todos estos elementos; este componente va colocado entre los clientes y los servidores, y por este motivo se denomina software intermedio o middleware.
© Editorial UOC
269
Capítulo VII. Introducción al software...
El software intermedio debe soportar diferentes protocolos e interfaces de comunicaciones y de acceso a los datos, así como permitir conexiones dinámicas entre clientes y servidores.
3.2. CORBA
El software distribuido se puede desarrollar con tecnología orientada a objetos y con tecnología clásica. Sin embargo, la forma en que funciona el software orientado a objetos, por medio de mensajes entre objetos que piden la ejecución de operaciones, se presta muy bien a la distribución; esto se debe a que un mensaje a un objeto que está en otro ordenador puede ser igual, en cuanto a la forma, que un mensaje a un objeto que está en el mismo ordenador, si se cuenta con la infraestructura necesaria para hacer llegar cada mensaje a su destinatario, esté donde esté. Dicho de otro modo, cualquier software orientado a objetos funciona por llamadas a operaciones entre un objeto que actúa de cliente y otro que actúa de servidor; observad que decimos actúa y no es porque el mismo objeto puede hacer de cliente en una llamada y de servidor en otra. La Common Object Request Broker Architecture (CORBA) es una arquitectura para sistemas de objetos distribuidos desarrollada por la OMG. Comprende las especificaciones de un software intermedio orientando a objetos diseñado para ofrecer portabilidad e interoperabilidad dentro de una red de sistemas heterogéneos. La OMG es la misma asociación que desarrolló UML.
3.2.1. Terminología básica
A continuación veremos algunos conceptos importantes para la descripción de CORBA: 1) Interfaz Sabemos que en el software orientado a objetos, y como consecuencia de su encapsulación, los objetos se comunican por medio de mensajes en los que se
© Editorial UOC
270
Ingeniería del software
piden operaciones y valores de atributos –estos dos elementos son públicos o, como mucho, protegidos– y que, por ello, se distingue entre una clase y la interfaz o interfaces que implementa. Sin embargo, en el caso de software no distribuido, el objeto cliente y el objeto servidor están en el mismo proceso y, por lo tanto, la interfaz y la clase que la implementa también; en el caso de software distribuido, el cliente y el servidor pueden estar en diferentes procesos e, incluso, en máquinas diferentes, y por lo tanto, en el proceso del cliente no encontramos la clase del servidor, sino sólo su interfaz. Está claro que continúa habiendo una clase que implementa la interfaz, pero esta clase no es visible desde el cliente (sólo su interfaz, como ya hemos dicho). De este modo, el software intermedio –y por lo tanto CORBA– sólo considera las interfaces, ya que el concepto de clase no se necesita para la comunicación entre objetos clientes y objetos servidores; este concepto tampoco es necesario para la implementación, ya que son los objetos y no las clases los que implementan las interfaces, porque cualquier operación se pide a un objeto concreto. Además de las interfaces de los objetos de la aplicación, que son propias de cada aplicación, hay interfaces estándar, cuya definición forma parte de las especificaciones de CORBA. Estas interfaces se utilizan en las comunicaciones entre la aplicación y los componentes de CORBA, así como entre estos componentes. Las interfaces en CORBA y en UML El concepto de interfaz en CORBA es muy parecido al de UML (lo cual es lógico, ya que la misma organización los ha especificado a ambos; sin embargo, CORBA no hace referencias a UML). Como diferencias un poco significativas, encontramos que las interfaces de UML no incluyen atributos y las de CORBA sí (pero esta diferencia no tiene ninguna repercusión efectiva, ya que un atributo puede ser sustituido por dos operaciones, una que le pone el valor y otra que lo lee), y que en CORBA no hay operaciones ni atributos de clase.
Entre interfaces se produce herencia: las denominadas interfaces derivadas heredan de las respectivas interfaces básicas. Puede darse el caso de interfaces abstractas, parecidas a las clases abstractas en el sentido de que no tienen atributos
© Editorial UOC
271
Capítulo VII. Introducción al software...
porque no puede haber objetos que las satisfagan directamente, sino sólo mediante interfaces derivadas de ellas. Herencia múltiple entre las interfaces Puede darse herencia múltiple –por lo menos, la hay entre las interfaces estándar mencionadas– pero es estrictamente aditiva (es decir, no hay coincidencia de nombres entre las operaciones o atributos que se heredan de interfaces básicas diferentes). En las interfaces estándar se dan algunos casos de polimorfismo; en estos casos, operaciones del mismo nombre se comportan en el caso de la interfaz derivada de forma diferente que en el caso de la interfaz básica.
2) Objeto Dentro de este modelo, un objeto es una entidad que proporciona servicios (operaciones) a las entidades que se los pidan (los clientes). Los objetos tienen identidad, interfaz e implementación. 3) Referencia a un objeto Una referencia a objeto es algo que identifica el mismo objeto cada vez que se utiliza; un objeto puede tener varias referencias diferentes. El formato y el valor de las referencias a objetos pueden depender del ORB. La unidad de las referencias No es obligado que no pueda haber nunca dos objetos con la misma referencia, pero sí que lo es que no pueda haberlos dentro de un ámbito espacial y temporal suficientemente amplio como para que los conflictos sean prácticamente imposibles.
4) Tipo de objeto Un tipo de objeto es un tipo cuyos miembros son referencias a objetos. Un tipo de objeto corresponde a una interfaz, en el sentido de que los objetos correspondientes a las referencias de un tipo satisfacen la interfaz correspondiente. 5) Petición (request) La petición es el mensaje de un objeto cliente a un objeto servidor para solicitar la ejecución de un método de este último objeto. Una petición comprende la identificación del objeto que la debe hacer, una operación, cero o más argu-
© Editorial UOC
272
Ingeniería del software
mentos que correspondan a los parámetros de la operación definidos en la interfaz utilizada y, eventualmente, un contexto. Los parámetros de las operaciones son esencialmente como los de las operaciones en UML; se identifican por posición y cada uno tiene un modo (in, out o inout) y un tipo. El resultado, si lo hay, es un parámetro out especial. La invocación de una petición se puede dar de las dos formas siguientes: • Estática, y entonces la interfaz que se utiliza queda determinada en tiempo de compilación. • Dinámica, y entonces la interfaz no se determina hasta el tiempo de ejecución (si bien la interfaz se debe haber compilado antes). 6) Operación y método Dentro de una petición se invoca una operación de una interfaz, pero lo que se ejecuta realmente es un método que forma parte de la implementación del objeto servidor al que está dirigida la operación. 7) Object Request Broker (ORB) Teniendo en cuenta que CORBA es una arquitectura de objetos distribuida con software intermedio, es lógico que su núcleo sea un componente responsable de la distribución de mensajes entre objetos; este componente se denomina Object Request Broker (ORB); el ORB es responsable de encontrar el objeto servidor dentro de la red, de prepararlo para recibir la demanda, de transmitirlo y de hacer llegar al cliente los datos devueltos como resultado de la petición o su respuesta. La actividad del ORB hace que el objeto cliente sólo tenga que conocer la interfaz y el valor de una referencia que lo identifique entre los demás para invocar una petición sobre un objeto servidor, pero no el lugar ni el lenguaje en que está programado.
3.2.2. Arquitectura de CORBA
La siguiente figura representa la arquitectura de CORBA:
© Editorial UOC
273
Capítulo VII. Introducción al software...
3.2.3. Descripción de los componentes de la arquitectura
A continuación, haremos una descripción de los componentes de la arquitectura que estamos considerando: • Aplicaciones del cliente: por medio de CORBA, los clientes efectúan peticiones con las que solicitan operaciones sobre objetos de los servidores me-
© Editorial UOC
274
Ingeniería del software
diante invocación estática o dinámica. Con las dos formas de invocación se pueden hacer las mismas demandas, y el servidor no puede saber si se ha utilizado una u otra. • Stub: debe haber uno para cada interfaz utilizada; establece la correspondencia entre las operaciones definidas en la interfaz y las rutinas que dependen del lenguaje de programación que llama la aplicación del cliente cuando hace una petición. Se genera a partir de la interfaz descrita en IDL, y se enlaza con la aplicación. Los lenguajes de programación orientados a objetos no necesitan stubs. • ORB al cliente: como hemos visto, el ORB aísla el objeto servidor y actúa como intermediario para las demandas, de forma que no es necesario que el cliente y el servidor tengan información uno del otro. El ORB al cliente se enlaza con la aplicación y verifica los argumentos de la demanda, los compara con los parámetros de la interfaz y envía la petición al servidor. Dentro de una arquitectura CORBA puede haber más de un ORB al mismo tiempo, con estilos de invocación diferentes y referencias a los objetos con una estructura diferente también; entonces, cada ORB debe saber encontrar su implementación de un objeto solicitado por un cliente sin que éste se lo tenga que indicar. • Depósito de interfaces: contiene las interfaces, así como las constantes y definiciones de tipo que se utilizan. • ORB al servidor: recibe las peticiones de ejecución de módulos, da formato a los argumentos e invoca la ejecución del método a partir del esqueleto. Se enlaza con la aplicación del servidor. • Portable Object Adapter (POA): los adaptadores de objetos llevan a cabo tareas generales relativas a la implementación de los objetos; por ejemplo, activar los objetos y sus implementaciones a partir de referenciarlos, desactivarlos, registrar las implementaciones disponibles en los servidores diferentes, generar los identificadores de los objetos (si no se encarga de ello la aplicación) e interpretar las referencias a estos objetos mediante estos identificadores. Para conseguir todas estas tareas, se aplican varias opciones, que son las denominadas políticas del adaptador. Los adaptadores de objetos se enlazan con la aplicación. En un momento determinado puede haber varios POA que formen una jerarquía para un ORB, cada uno de los cuales gestiona un grupo de objetos; de éstos, el POA raíz se pone en funcionamiento auto-
© Editorial UOC
275
Capítulo VII. Introducción al software...
máticamente, y los demás lo hacen según la jerarquía por medio del activador del adaptador. Adaptador de objeto en CORBA Las primeras versiones de CORBA especificaban otro adaptador de objetos en lugar del POA: el BOA (Basic Object Adapter).
• Aplicaciones al servidor: incluyen una implementación o más de los objetos y de sus métodos y, obviamente, también el código para el inicio y la finalización de la misma aplicación. • Métodos: cada método es el código, contenido en la implementación de un objeto, que implementa una determinada operación de una interfaz. El conjunto de las implementaciones de las operaciones de una interfaz –y, por lo tanto, el conjunto de los métodos correspondientes– se denomina sirviente (en inglés, servent). Para una misma interfaz puede haber varios sirvientes y, por lo tanto, una operación de una interfaz puede ser implementada por varios métodos. La implementación de los objetos debe ser independiente del ORB. • Esqueletos: son correspondencias, dependientes del lenguaje de programación y del ORB, que se establecen entre las definiciones de operaciones de IDL y los métodos correspondientes y las implementaciones que los contienen; incluyen la programación necesaria para lanzar los métodos imprescindible para una petición. Se generan en forma fuente a partir de la definición de la interfaz respectiva, se compilan y se enlazan con la aplicación del servidor. Los utilizan los adaptadores de objetos. Además de los esqueletos que establecen relaciones permanentes entre operaciones y métodos, o esqueletos específicos del tipo, también puede haber esqueletos dinámicos, que acceden en tiempo de ejecución al código de la operación y a sus parámetros. • Servicios de objetos y servicios comunes: se describen aparte. • Depósito de implementaciones: contiene información que permite al ORB localizar y activar las implementaciones de un objeto al que se ha hecho referencia, y encuentra las interfaces pedidas dentro del depósito de interfaces.
© Editorial UOC
276
Ingeniería del software
3.2.4. El procesamiento de las demandas: visión resumida El procesamiento de las peticiones tiene las siguientes fases: 1) El cliente invoca la petición. 2) Cuando llega al ORB, la demanda incluye una referencia al objeto que es su destinatario. El ORB, utilizando el depósito de implementaciones, localiza el proceso del servidor o lo pone en funcionamiento si es necesario. 3) El ORB localiza el POA correspondiente al objeto destinatario de la demanda, o bien pide su creación al activador del adaptador; si no lo consigue, el cliente recibirá la excepción object_not_exist. 4) El POA localiza o activa el sirviente del objeto de formas distintas según las políticas vigentes. Una vez que el sirviente está activo, el POA selecciona dentro de éste el método correspondiente a la operación invocada dentro de la petición. 5) Se localiza el esqueleto. 6) Se hace la gestión de las respuestas y las excepciones.
3.2.5. IDL Las interfaces utilizadas dentro del entorno de CORBA se definen mediante la Interface Definition Language (IDL). Otros lenguajes IDL En el mismo seno de la tecnología de sistemas distribuidos se encuentran otros lenguajes que también se denominan IDL.
IDL no es un lenguaje de programación, y no está pensado para que se pueda generar código objeto o ejecutable a partir de sí mismo; sin embargo, las implementaciones de CORBA acostumbran a poder generar código fuente –principalmente en C++, pero también en lenguajes como por ejemplo COBOL, Smalltalk y Java– a partir de IDL. La compilación de una interfaz definida con este lenguaje genera tres salidas: • un stub;
© Editorial UOC
277
Capítulo VII. Introducción al software...
• un esqueleto; • un fichero de cabecera, que contiene definiciones de tipos de datos como estructuras y constantes, y se incluye dentro de las aplicaciones de los clientes y de los servidores. Además, la interfaz compilada queda depositada en el denominado depósito de interfaces. La gramática de IDL es un subconjunto de la norma que se ha propuesto sobre C++ ANSI, ampliado para soportar el mecanismo de invocación de peticiones. IDL es un lenguaje declarativo y contiene la sintaxis de C++ para la declaración de constantes, tipos y operaciones (si bien en algunos aspectos la sintaxis de IDL es más restrictiva). Las especificaciones de IDL
Una especificación de IDL es un fichero fuente, que puede contener definiciones de módulos, interfaces, tipos de valores, constantes y excepciones. Los tipos de valores... ... son tipos con posibilidad de herencia, cuyos valores no tienen identidad.
Los módulos agrupan definiciones de interfaces y sirven principalmente para definir ámbitos de validez de los nombres dentro de una especificación; en general, las referencias a nombres de elementos definidos dentro de un módulo deben llevar como prefijo el nombre del módulo. Hay un módulo especial, CORBA, que reúne todos aquellos nombres que forman parte de las especificaciones de CORBA.
3.2.6. Conexión de una aplicación en el entorno CORBA
Para que una aplicación pueda entrar en el entorno de CORBA, antes es necesario hacer lo siguiente: • Inicializarla dentro del entorno de un ORB o más –primero– y después tal vez también dentro del respectivo entorno del adaptador de objetos.
© Editorial UOC
278
Ingeniería del software
• Obtener referencias al pseudoproyecto del ORB y, eventualmente, también a otros objetos como el POA raíz, el POA Current, el depósito de interfaces y algunos servicios de objetos, para posteriormente pedirles operaciones.
3.2.7. Las invocaciones dinámicas
Las invocaciones dinámicas son invocaciones de peticiones en las que la petición se crea en tiempo de ejecución, a diferencia de las invocaciones estáticas, en las que la petición queda determinada en tiempo de compilación. En la invocación dinámica de peticiones se pueden utilizar dos modos de comunicación: síncrono y síncrono diferido. Una invocación dinámica gestionada por CORBA tiene típicamente los siguientes pasos: 1) Obtención de la información sobre la interfaz del objeto. 2) Creación de la estructura de datos que se pasará al objeto. 3) Creación de una petición para el objeto. 4) Invocación de la petición.
3.2.8. La interfaz de esqueletos dinámicos (DSI)
Cuando se utilizan esqueletos dinámicos, a diferencia de los específicos de un tipo, el nombre de la operación e incluso el tipo del objeto, no se conocen hasta la ejecución. En cierto modo, se trata de un caso simétrico, por parte del servidor, de lo que es la invocación dinámica por parte del cliente; del mismo modo que un servidor no sabe si el cliente ha utilizado invocación estática o dinámica, un cliente no sabe si el servidor utiliza un esqueleto específico del tipo o dinámico. Junto con la invocación dinámica, los esqueletos dinámicos son una forma de conseguir puentes genéricos entre ORB. Otras utilidades de los esqueletos dinámicos son las herramientas interactivas de desarrollo del software basadas en intérpretes, las herramientas de prueba
© Editorial UOC
279
Capítulo VII. Introducción al software...
y los monitores que se interponen dinámicamente entre los objetos, y los lenguajes de tipificación dinámica, como por ejemplo LISP. Para todas las peticiones a un mismo objeto se utiliza la misma rutina, denominada rutina de implementación dinámica (DIR); para un mismo lenguaje de programación, todas las llamadas a la DIR tienen los mismos argumentos. DIR es la sigla de la expresión inglesa correspondiente a rutina de implementación dinámica.
3.2.9. Los servicios de objetos
Características comunes
A pesar de no formar parte del entorno CORBA en sentido estricto, la forma en que se utilizan los objetos en las especificaciones de los servicios de objetos respeta muchos de sus principios: • Se utilizan interfaces para tipificar los objetos. • Hay una separación clara entre la interfaz y la implementación; los clientes sólo ven las interfaces, pero no sus implementaciones. • Se utiliza la herencia –incluso múltiple– entre interfaces para extender y especializar la funcionalidad, y permitir su evolución. Además, el diseño de los servicios de objetos respeta, en líneas generales, los siguientes principios: • Son servicios genéricos, en el sentido de que son independientes del tipo del cliente y también –en general– del tipo de datos pasados en las peticiones. • Generalmente, están implementados en forma de objetos de CORBA que se pueden activar local o remotamente. • Con frecuencia, las interfaces permiten implementaciones con diferentes calidades de servicio. • Muchos servicios tienen interfaces diferentes para tipos de clientes diferentes. • Los servicios utilizan con frecuencia interfaces callback; es decir, hacen peticiones al cliente mediante interfaces que éste debe soportar. De este mo-
© Editorial UOC
280
Ingeniería del software
do, también se aprovechan las ventajas de las interfaces en las llamadas al cliente. • Las excepciones sólo sirven para comunicar situaciones anómalas. Los códigos de retorno normales se pasan al cliente por medio de parámetros de salida. • Generalmente, hay operaciones distintas en lugar de varias modalidades de una operación diferenciadas, por ejemplo, por un parámetro de indicadores. El servicio de nombres
El servicio de nombres gestiona estructuras de nombres de objetos que sirven para localizarlos desde otros objetos. Un objeto puede tener varios nombres. Una asociación entre un objeto y su nombre es un name binding. Un contexto de nombres (en inglés, naming context) es un espacio de nombres en el que los nombres de los objetos no se pueden repetir. Un contexto de nombres, que es un objeto, tiene nombre dentro de otro contexto de nombres, y de este modo se pueden constituir jerarquías –eventualmente distribuidas– de nombres que dan lugar a nombres compuestos, constituidos por una secuencia de los mismos, en la que todos excepto el último (el nombre simple) pertenecen a contextos de nombres. Un componente consta de un atributo identificador y un atributo de clase (en inglés, kind attribute), que hace una tipificación de los nombres; esta tipificación no tiene valor sintáctico para permitir nombres vinculados a los lenguajes de programación o idiomas concretos. El servicio de acontecimientos
Por lo que respecta a CORBA, un acontecimiento es un hecho que guarda relación con un objeto y tiene interés para otros objetos, a los que se hace accesible mediante un mensaje denominado notificación. La notificación no la hace el objeto –que no tiene por qué saber que hay objetos interesados en saber que se ha producido el acontecimiento–, sino el servicio de acontecimientos. Este servicio distingue dos tipos de objetos: suministradores (en inglés, suppliers), que generan acontecimientos, y consumidores, que los procesan. Además, puede haber un tercer tipo de objetos: los canales de acontecimientos, que
© Editorial UOC
281
Capítulo VII. Introducción al software...
son consumidores y suministradores al mismo tiempo, y permiten que varios suministradores se comuniquen con diversos suministradores sin que se conozcan entre sí. Los acontecimientos con tipo (en inglés, typed events) posibilitan que las aplicaciones describan el contenido de los acontecimientos por medio de IDL, con parámetros sólo de entrada y sin retorno. En este caso, puede haber dos canales de acontecimientos en serie, uno de los cuales puede filtrar los acontecimientos para el otro basándose en el tipo. Para la notificación hay dos mecanismos: 1) Push, en el que el suministrador toma la iniciativa de transmitir información sobre el acontecimiento a los consumidores, ya sea directamente o mediante un canal de acontecimientos; el consumidor se puede “suscribir” a los acontecimientos de un tipo determinado y también puede decidir dejar de recibir acontecimientos. 2) Pull, en el que el consumidor que pide la información sobre el acontecimiento al suministrador, ya sea directamente o mediante un canal de acontecimientos; el consumidor puede preguntar periódicamente por los acontecimientos, mientras que el suministrador puede registrar el identificador del consumidor y ofrecer sus servicios; también puede dejar de aceptar demandas sobre acontecimientos. Cuando la notificación tiene lugar mediante un canal de acontecimientos, también puede ser mixta: push entre consumidor y canal y pull entre canal y suministrador, o al revés. Los consumidores y suministradores se deben haber puesto de acuerdo en lo que respecta a la semántica de los acontecimientos, pero el canal de acontecimientos no la conoce. El servicio de notificaciones
Es una extensión del servicio de acontecimientos con las funciones adicionales siguientes: • La transmisión de acontecimientos con estructuras de datos complejas llamados acontecimientos estructurados.
© Editorial UOC
282
Ingeniería del software
• La posibilidad de añadir filtros a los proxies para que los clientes puedan especificar qué acontecimientos quieren recibir. •
La posibilidad que los suministradores de un canal sepan qué tipo de acontecimiento quieren recibir los consumidores de este canal.
• La posibilidad que los consumidores de un canal sepan qué tipos de acontecimiento ofrecen los suministradores de este canal para que los puedan pedir. • La posibilidad que haya diferentes calidades de servicio a nivel de canal, proxy y acontecimiento. • Un depósito opcional de tipos de acontecimientos que permita que los usuarios creen filtros de acontecimientos en un lenguaje que se especifica. Los acontecimientos estructurados se definen por dominios (finanzas, por ejemplo), en el sentido que cada dominio puede tener definidos sus tipos de acontecimientos y que los nombres de estos tipos se pueden repetir en dominios diferentes. Cada acontecimiento que se produce puede tener un nombre que no tiene significado para el servicio sino sólo para el usuario. Los filtros son objetos que sirven para seleccionar los acontecimientos por medio de restricciones expresadas o bien en un lenguaje estándar o bien en uno propio del implementador. El servicio de relaciones
El servicio de relaciones permite crear relaciones, permanentes y temporales, entre dos objetos o más, sin modificarlos y sin que éstos lo sepan. El concepto de relación en este servicio es similar al de asociación en UML. Hay tres niveles de servicio: 1) El nivel de base define relaciones y papeles. 2) El nivel de grafos considera grafos de objetos relacionados (es decir, conectados por relaciones); en este nivel se definen objetos nodos y objetos de recorrido de un grafo, que permiten recorrer un grafo sin activar sus objetos. 3) El tercer nivel considera dos tipos específicos de relaciones: por contenido y por referencia.
© Editorial UOC
283
Capítulo VII. Introducción al software...
El servicio de ciclo de vida
El servicio de ciclo de vida proporciona operaciones para crear, copiar, mover y borrar objetos de forma local o remota; además, soporta asociaciones entre grupos de objetos (ya sean por contenido o por referencia) y condiciones de integridad referencial entre objetos. Para crear un objeto es necesario que el cliente encuentre un objeto factoría –es decir, un objeto que sabe cómo se crea un objeto de la clase correspondiente–, que emita una petición de creación y que obtenga el identificador del objeto creado. El objeto factoría debe asignar los recursos necesarios, obtener el identificador del objeto y registrar el nuevo objeto mediante el adaptador de objetos y el depósito de implementaciones. También se puede crear un objeto copiándolo. El servicio de propiedades
El servicio de propiedades sirve para definir atributos de los objetos dinámicamente, en contraste con las interfaces de IDL, que lo hacen estáticamente. Los atributos dinámicos o propiedades tienen un nombre, un tipo y un valor que se puede leer y modificar, así como un modo de propiedad, que puede tomar estos valores: • normal, es decir, sin restricciones; • read-only, que sólo deja leer y borrar; • fixed-normal, que deja modificar pero no borrar; • fixed-readonly, que sólo deja leer. El servicio de tiempo
El servicio de tiempo se utiliza para obtener la hora, confirmar el orden en que se han producido diferentes acontecimientos, generar acontecimientos relativos al tiempo y calcular el tiempo transcurrido entre dos acontecimientos. La representación de tiempo UTC El servicio de tiempo utiliza la representación del tiempo denominada Universal Time Coordinated (UTC), definida dentro de la especificación X/Open DCE Time Service, en la que la unidad son cien nanosegundos y la base son las cero horas (hora de Greenwich) del 15.10.82.
© Editorial UOC
284
Ingeniería del software
El servicio de tiempo integra dos servicios: • El servicio básico de la hora (en inglés, Basic Time Service): comprende operaciones para obtener y manipular la hora. • El servicio de acontecimientos de temporización (en inglés, Timer Event Service): proporciona operaciones para implementar gestores de acontecimientos disparados por tiempo y gestionar los acontecimientos que generan. El servicio de externalización
Externalizar un objeto quiere decir convertirlo en un objeto stream, e internalizarlo quiere decir hacer lo contrario; el servicio de externalización sirve para las dos cosas. Un objeto stream es un área de datos con un cursor, que está en memoria o en disco o se envía a la red. La externalización sirve para facilitar la exportación/importación de un objeto de un proceso, ordenador u ORB a otro (o al mismo proceso), en el que se hará una internalización para crear un nuevo objeto. El servicio de estados persistentes
Su función es guardar el estado de un objeto en memoria permanente y recuperarlo. Para el cliente del objeto es transparente el hecho que este esté en memoria o que haya de ser recuperado del almacenamiento permanente. El sistema de almacenamiento tiene estos componentes: • Los objetos de almacenamiento: es la forma en qué este servicio presenta la información persistente. Cada objeto de almacenamiento tiene un tipo, al cual hay asociados atributos de estado y operaciones de estado; entre estos tipos puede haber herencia. • Los almacenes de datos (datastores): son las implementaciones que almacenan la información persistente de un objeto como una base de datos o un conjunto de ficheros. • Un almacén de datos se compone de storage homes, cada uno de los cuales almacena objetos de almacenamiento de un solo tipo; cada storage home tiene un tipo, que consta del tipo de objetos de almacenamiento que puede contener y de operaciones y claves. Hay una jerarquía de tipos de storage homes
© Editorial UOC
285
Capítulo VII. Introducción al software...
paralela a la de los tipos de los objetos de almacenamiento respectivos; un (tipo de) storage home y todos los que se deriven constituye una familia de storage homes. En un almacén de datos cada storage home gestiona no solamente sus objetos de almacenamiento sino los de todos los tipos de la familia que encabeza. Cada objeto de almacenamiento tiene un identificador no repetido en su storage home (short-pid) y un identificador global (pid), no repetido en del catálogo (ver el apartado siguiente). • Una clave es una lista de miembros de estado de un tipo de objetos de almacenamiento que constituye un identificador no repetido de los objetos de este tipo; un storage home puede tener cualquier número de claves. • Los catálogos gestionan storage homes, los cuales a su vez gestionan objetos de almacenamiento. Hay dos clases de catálogos: – session pools, – sesiones, que son conexiones lógicas entre un proceso y un almacén de datos o más; se puede controlar por programa la asignación de las sesiones y su asociación a transacciones. Las sesiones pueden ser transaccionales o no; las transaccionales están asociadas a recursos, que son transacciones de almacén de datos. • Los conectores son objetos locales que crean los catálogos. Están registrados en un registro de conectores único por ORB que soporta la interfaz ConectorRegistry. La especificación del almacenamiento se puede hacer de dos maneras: • mediante un lenguaje especial llamado PSDL (Persistente State Definition Language), que es una extensión de IDL; • mediante traducciones estándar a Java o C++ de las instrucciones de PSDL (persistencia transparente). El servicio de control de la concurrencia
La finalidad del servicio del control de la concurrencia es arbitrar los accesos concurrentes a un objeto con la intención de garantizar su integridad. Propor-
© Editorial UOC
286
Ingeniería del software
ciona interfaces para que los clientes puedan reservar y liberar recursos para coordinarse en su uso compartido. Este servicio puede funcionar en dos modos: • Transaccional, es decir, en representación de una transacción; entonces, el servicio de transacciones se encarga de la liberación de los recursos reservados cuando la transacción acaba, ya sea de forma normal o anormal. • No transaccional; es decir, en representación del hilo que se ejecuta en cada momento, que no tiene por qué ser una restricción; entonces, el mismo servicio de control de la concurrencia es el que se encarga de llevar a cabo las liberaciones cuando es necesario. Está diseñado para funcionar en combinación con el servicio de transacciones de objetos y puede soportar transacciones encajadas. No se define qué es un recurso; es responsabilidad de los clientes de este servicio tanto definir los recursos como identificar sus usos potencialmente conflictivos; en el caso más típico, los recursos son objetos. Es posible que haya recursos de varios niveles o granularidades; es decir, recursos que contienen otros recursos. Sin embargo, el servicio no ve estas jerarquías. Se puede optar por definir pocos recursos de alto nivel o muchos de bajo nivel; en el primer caso es preciso hacer menos reservas, pero los conflictos serán más frecuentes. Equivale a reservar ficheros enteros en lugar de registros individuales.
Tampoco se define qué es cada transacción; esto lo hace el servicio de transacciones. Se considera que en los clientes transaccionales cada transacción tiene un solo hilo, y que una transacción no se ejecuta para más de un hilo al mismo tiempo. Un solo hilo por transacción no impide el paralelismo, ya que hay soporte para transacciones encajadas (consultad el servicio de transacciones más adelante).
Una reserva (lock) es la capacidad de un cliente concreto de acceder a un recurso determinado de un cierto modo; una reserva corresponde, por lo tanto, a un cliente y un recurso. Un cliente debe conseguir una reserva sobre un recurso
© Editorial UOC
287
Capítulo VII. Introducción al software...
antes de acceder a él; dado que existen reservas de distintos modos, el cliente debe pedir la reserva de una forma que le permita llevar a cabo las actividades previstas sobre el recurso. El arbitraje mencionado en la definición del servicio consiste en evitar que varios clientes tengan al mismo tiempo reservas del mismo recurso si las actividades de estos clientes pudieran entrar en conflicto. El servicio concederá una reserva a un cliente sólo si ningún otro tiene un reserva de un modo incompatible con el de la reserva que se pide ahora. Otro aspecto es el de la liberación de recursos reservados (en inglés, unlocking). Si se piden reservas en una transacción, el servicio de transacciones libera los recursos cuando ésta acaba; si se piden reservas fuera de transacciones, el cliente debe liberar explícitamente los recursos reservados. Con frecuencia, las reservas se mantienen hasta el final de la transacción, pero en el caso de que una transacción no modifique el recurso, lo puede liberar cuando ya sabe que no lo necesitará más. Locksets
Cada lockset es un conjunto de reservas sobre un mismo recurso; los clientes deben asignar un lockset a cada recurso. También encontramos unos coordinadores de reservas, cada uno de los cuales puede gestionar locksets sobre recursos de un mismo tipo que deban ser liberados cuando se acaba una misma transacción. La creación de locksets y la liberación de recursos cuando una transacción se confirma o se aborta es responsabilidad del cliente. El servicio de transacciones
Las transacciones son unidades de proceso que o bien llegan a acabar normalmente, o bien, en el caso de que se vean abortadas, las actualizaciones en bases de datos que hubiesen hecho se anulan, como si no hubiesen empezado. El servicio de transacciones tiene las siguientes funciones: • Controlar el alcance y la duración de las transacciones. • Permitir que participen varios objetos en una sola transacción. • Permitir que estos objetos asocien sus cambios de estado a una transacción. • Coordinar el término de las transacciones.
© Editorial UOC
288
Ingeniería del software
El servicio de transacciones soporta dos modelos de transacción: • Transacciones encajadas de cualquier número de niveles. Una subtransacción puede confirmar o anular (a petición de cualquiera de los objetos que participen en la misma), sin que necesariamente lo hagan las subtransacciones que la contienen, pero su confirmación no será definitiva mientras la transacción no confirme. Una transacción sólo puede confirmar cuando lo hayan hecho todas sus subtransacciones; además, cuando la transacción es anulada, también lo son todas sus subtransacciones. • Transacciones planas según el modelo DPT de X/Open, que no pueden tener subtransacciones. El servicio de seguridad
El servicio de seguridad tiene estos aspectos: • Confidencialidad: que sólo tengan acceso a la información los usuarios autorizados. • Integridad: que la información sólo pueda ser modificada por los usuarios autorizados y de la forma autorizada. • Responsabilidad: que los usuarios sean responsables de sus acciones en relación con la seguridad. • Disponibilidad: que el acceso al sistema no se pueda negar injustificadamente a los usuarios. Las funciones de este servicio son las siguientes: • Identificación: pedir al principal (el principal es una persona u objeto titular de una autorización de acceso) que diga quién es. • Autenticación: comprobar que el principal es quien dice que es. • Autorización de los principales. • Control de acceso: determinar si se debe permitir el acceso de un principal (previamente identificado y autenticado) a un objeto a partir de los atributos de uno y otro. • Auditoría de seguridad: determinar a los principales responsables de las acciones en materia de seguridad e identificarlos incluso mediante una cadena de peticiones. • Seguridad de la comunicación entre objetos, que requiere la autenticación mutua de cliente y servidor.
© Editorial UOC
289
Capítulo VII. Introducción al software...
• No-repudiación: suministrar pruebas irrefutables del origen de los datos y de su recibimiento por el destinatario. • Gestión de las políticas de seguridad. El servicio tiene estos niveles de funcionalidad: 1) El nivel 1, que proporciona servicios de seguridad a aplicaciones que no tienen conocimiento de ello y a aplicaciones que tienen unas necesidades reducidas de control y auditoría de la seguridad; comprende la seguridad de las invocaciones, la protección de los mensajes, algunas posibilidades de delegación, control y auditoría. 2) El nivel 2, que permite a las aplicaciones controlar la seguridad en las invocaciones de objetos y soporta una gestión de seguridad portátil. 3) La funcionalidad opcional, de la cual las especificaciones actuales sólo incluyen la no-repudiación. El servicio de colecciones
Las colecciones son tipos diferentes de agrupaciones de objetos (elementos). Típicamente, los elementos de una colección o bien son del mismo tipo o bien tienen una misma interfaz. Los diferentes tipos de colecciones difieren en lo que respecta a la existencia de una ordenación de los objetos, la existencia de acceso a los objetos por clave, la existencia de un criterio de igualdad de los objetos y sobre si puede haber o no varios objetos con el mismo valor de la clave; diferentes combinaciones de estas restricciones dan lugar a tipos distintos de colecciones; a cada tipo de colección le corresponde una interfaz, y todas ellas constituyen una jerarquía de derivación en la que los niveles, a excepción del más bajo, son interfaces abstractas. Para recorrer los objetos de las colecciones, existen unos cursores denominados iteradores; hay un tipo diferente de ellos para cada interfaz abstracta de colecciones. El servicio de consultas
Las consultas no se limitan sólo a accesos de lectura como podría parecer, sino que son instrucciones declarativas con predicados, que pueden comprender valores de atributos e invocaciones y otros servicios de objetos.
© Editorial UOC
290
Ingeniería del software
El resultado de una consulta puede ser una colección obtenida por medio de la selección de aquellos objetos de una colección fuente (que también podría ser el resultado de una consulta anterior) que cumplen un predicado dado o bien puede provenir de un evaluador de consultas a partir de un predicado que se evaluaría por encima de una colección virtual. El servicio de consultas puede coordinar varios evaluadores encajados y federados. Los objetos pueden participar en el servicio de dos formas: 1) A título individual; entonces el evaluador de consultas se encarga de evaluar el predicado de la consulta y de llevar a cabo todas las operaciones de la consulta por medio de operaciones definidas en la interfaz correspondiente a los objetos. Éste es el mecanismo más general, pero también el menos optimizado. En este caso, los objetos afectados constituirían una colección virtual de las que hemos hablado. 2) Como elementos de una colección, que soporta una interfaz para consultas; el evaluador le pasa el predicado y esta interfaz lo evalúa, hace las operaciones sobre los objetos individuales, combina los resultados y transmite el resultado definitivo al objeto que lo había invocado. Este mecanismo permite que los evaluadores apliquen sus instrumentos de optimización. La especificación del servicio de consultas no define mecanismos de evaluación, indexación ni optimización, pero sí prevé lenguajes de consulta concretos, que son los siguientes: • SQL-92 Query y sus sucesores. • OQL-93 y OQL-93 Basic, del ODMG, y sus sucesores. Algunas características destacadas del servicio de consultas son las siguientes: • Proporciona operaciones para seleccionar, insertar, actualizar y borrar elementos dentro de colecciones. • Los elementos afectados pueden ser objetos persistentes o transitorios, locales o remotos.
© Editorial UOC
291
Capítulo VII. Introducción al software...
• En los predicados se pueden utilizar atributos, herencia y navegación mediante relaciones, todo por medio de las interfaces de los objetos elementos. El servicio de licencias
En el mundo de los objetos distribuidos podemos encontrar objetos de pago; entonces conviene que sea posible medir el uso de los objetos con vistas a una posterior facturación. El servicio de licencias da apoyo a esta función. Se consideran los siguientes tipos de licencias: con periodo de gracia, con listas de usuarios, con licencias reservadas siempre disponibles y con licencias multiuso. Desde otro punto de vista, licencias para una máquina, licencias en el ámbito de instalación y licencias flotantes para un número máximo de usuarios concurrentes. El servicio de licencias debe cumplir unas características necesarias para optimizar su rendimiento: • Posibilidad de crecimiento. • Medidas para evitar que queden licencias asignadas indefinidamente a una aplicación. • Garantía de que sólo se utilicen las licencias compradas. • Prevención de clientes y servidores impostores. Un productor (en inglés, producer) es una empresa o persona que tiene la propiedad intelectual cuyo uso se quiere controlar. Un cliente del productor (en inglés, producer client) es cualquier objeto cuyo uso de una licencia debe ser controlado. Una política del productor (en inglés, producer policy) es un conjunto de datos que describe los términos y las condiciones detalladas que rigen el control del uso de una licencia. Un documento de licencia proporciona un medio para especificar las limitaciones en el uso de la licencia: número de ejemplares de la propiedad intelectual, limitaciones temporales, etc. El servicio del intermediario de objetos (Object Trader)
Un objeto que presta unos servicios determinados (exportador) pide ser registrado y, por ello, para cada servicio comunica la oferta de servicio, que con-
© Editorial UOC
292
Ingeniería del software
tiene el número del tipo de servicio, una referencia a la interfaz que proporciona el servicio y los valores de las propiedades del servicio. Entonces se dice que el objeto exporta estos servicios.
La información sobre cada tipo de servicio con el que trata un objeto intermediario determinado comprende un tipo de interfaz y, opcionalmente, un tipo de propiedad o más. Un tipo de servicio puede ser subtipo de otro. Se retorna un identificador de la oferta al exportador, que le permite modificarla o retirarla posteriormente. Los clientes (importadores) pueden obtener una lista de servicios disponibles (importarlos), en general, o bien del tipo de las páginas amarillas. Por ello se debe indicar el tipo de servicio deseado, y una restricción especificada en el lenguaje de restricciones (en inglés, standard constraid language), cuyos elementos principales son: tipos de valores de propiedades, operadores y literales. El intermediario busca el servicio que mejor se ajusta a lo que pide el cliente, pero es éste quien interactúa directamente con el proveedor que elige: utiliza el tipo de servicio, la restricción especificada y las preferencias que deben servir para establecer un orden de presentación al importador de las ofertas seleccionadas. Unas políticas permiten identificar el conjunto de ofertas de servicios dentro del cual se debe efectuar la búsqueda. Las políticas tienen un nombre y un valor. Se pueden crear federaciones de objetos intermediarios y, por lo tanto, de los dominios de tipos de servicio o particiones, en cuyo ámbito se propagan las consultas entre intemediarios.
3.2.10. Los servicios comunes (Common Facilities)
Los servicios comunes son servicios que pueden ser compartidos por las aplicaciones y que son de una naturaleza menos básica que los servicios de objetos. Se dividen en servicios horizontales, que son utilizables en la mayoría de las aplicaciones, y servicios verticales, que son específicos de un dominio o sector empresarial. Los servicios comunes horizontales son los siguientes: • de internacionalización, tiempo y servicios relacionados
© Editorial UOC
293
Capítulo VII. Introducción al software...
• de agentes móviles • mientras que los servicios verticales que se han especificado hasta ahora son éstos: • Healthcare (Person Identification Service, Lexicon Query Service) • Telecoms (Audio/Video Streams, CORBA TC Interworking and SCCP Inter-ORB Protocol, CORBA/TMN Interworking, Notification Service, Telecoms Log Service) • Finance (Currency, General Ledger) • Manufacturing (Distributed Simulation Systems, Product Data Management) • Transportation (Air Traffic Control). Sólo se tratará de los servicios horizontales. El servicio de internacionalización y tiempo y servicios relacionados
El servicio de Internacionalización se basa en las características locales (locales) de POSIX y X/Open, que son aspectos del entorno del usuario que dependen del idioma y las convenciones culturales. Los usuarios pueden escoger unas características locales por omisión. Se consideran las características locales del POSIX, que son éstas: • la clasificación de los caracteres y la conversión de las letras, • la ordenación alfabética, • el formato de los valores monetarios, • el formato de los valores numéricos no monetarios, • formatos de mensajes y respuestas interactivas. Se consideran caracteres ampliados como los de IDL. El servicio de agentes móviles
Pretende conseguir la interoperabilidad entre agentes móviles de diferentes fabricantes programados en el mismo lenguaje. Con vistas a este objetivo se estandarizan: • La gestión de los agentes por un administrador del sistema, con funciones como la creación de un agente de una clase determinada y suspensión, rearranque y cancelación del hilo de ejecución de un agente.
© Editorial UOC
294
Ingeniería del software
• La transferencia de agentes, que permite que dos agentes que se tendrán que comunicar durante la ejecución (por ejemplo, para la monitorización de datos) se coloquen en sistemas de agentes próximos físicamente. • Los nombres de agentes y de sistemas de agentes, a más de la estandarización de las operaciones y de las ubicaciones, para permitir identificar el agente del cual se pide una operación y determinar rápidamente si un sistema de agentes determinado puede soportar un agente que llega a él. • Las ubicaciones y los tipos de sistemas de agentes, para que un agente pueda acceder a información sobre un sistema de agentes y los sistemas de agentes se puedan identificar entre sí. Un agente es un programa (no necesariamente orientado a objetos) que actúa de manera autónoma en representación de una persona u organización. Los agentes se programan generalmente en lenguajes interpretados, como Java y Tcl, para conseguir portabilidad, y tienen su propio hilo de ejecución. Hay dos tipos de agentes: • Agentes estacionarios, cuya ejecución se completa en el mismo sistema donde ha empezado. Cuando se han de comunicar con agentes de otros sistemas o necesitan información externa a su sistema usan mecanismos como RPC, que pueden ser gestionados por sistemas de objetos distribuidos como CORBA, DCOM y RMI. • Agentes móviles, que pueden viajar del sistema en que se han arrancado al sistema donde hay un agente con el cual han de interactuar y también pueden utilizar los servicios de objetos de este último.
3.2.11. Interoperabilidad entre ORB
La interoperabilidad entre ORB pretende soportar la distribución y la intercomunicación de objetos entre copias e implementaciones de ORB diferentes que cumplan las especificaciones de CORBA. Se puede decir que así como un ORB hace posible que los objetos se envíen y reciban peticiones y respuestas de forma transparente, la interoperabilidad en-
© Editorial UOC
295
Capítulo VII. Introducción al software...
tre ORB extiende esta transparencia al caso en que los objetos mencionados están gestionados por ORB diferentes. La interoperabilidad se basa en los siguientes elementos: la arquitectura de la interoperabilidad, el soporte de puentes entre ORB y dos tipos de protocolos interORB: los generales (GIOP) y los de Internet (IIOP), además de protocolos específicos para determinados entornos, como por ejemplo el DCE (ESIOP). La arquitectura de la interoperabilidad
La arquitectura de la interoperabilidad proporciona un marco conceptual para identificar los elementos de la interoperabilidad y definir los aspectos que deben cumplir. También establece mecanismos y convenciones para conseguir la interoperabilidad entre ORB producidos de forma independiente; en particular, introduce el concepto de puentes interORB. En este contexto, un dominio es un conjunto de objetos (los miembros del dominio) que tienen una característica en común. Un objeto puede pertenecer a varios dominios. Un dominio es también un objeto. Hay dos tipos de dominios: • administrativos, como por ejemplo los dominios de nombres o los relacionados con recursos; • tecnológicos, vinculados a protocolos, por ejemplo. Entre dominios se pueden establecer dos tipos de relaciones: • de contención, cuando el ámbito de uno es subconjunto del ámbito de otro; • de federación, cuando los dominios se juntan por acuerdo de los respectivos gestores. Los puentes entre dominios
El interés del concepto de dominio para la interoperabilidad está en el hecho de que ésta consiste precisamente en superar las fronteras de los dominios, algo que se consigue mediante unas correspondencias o puentes entre dominios que permitan transformar las demandas expresadas en términos de un dominio en peticiones expresadas en términos del otro. Dado que el concepto de interoperabilidad es simétrico, es necesario que las transformaciones que los puentes soportan sean bidireccionales.
© Editorial UOC
296
Ingeniería del software
Puentes seguros entre dominios No siempre es deseable la transparencia total, ya que en ocasiones se establecen dominios precisamente por razones de seguridad o de gestión de recursos compartidos o compartibles; en estos casos, el puente debe incorporar los filtros necesarios.
Los puentes permiten que los ORB colaboren sin que deban tener en cuenta los detalles de la implementación del otro; también puede haber puentes que permitan la interoperabilidad con sistemas no basados en CORBA, como ocurre en el caso de COM de Microsoft. Además, los puentes pueden servir para determinadas situaciones transitorias, generación automática de implementaciones para un ORB a partir de implementaciones hechas para otro, etc. Existen dos tipos de puentes: a) Inmediatos, en los que los elementos de un dominio se transforman directamente en los del otro; es una opción adecuada cuando el cambio de dominio es puramente administrativo (es decir, cuando no hay cambio de tecnología). b) Intermediados; en este tipo de puentes, lo que se construye son “medios puentes” que realizan transformaciones entre los formatos internos de los dos dominios y un tercer formato; es una opción más flexible pero menos eficiente que la anterior.Por lo que respecta a su relación con los ORB, los puentes se pueden implementar de dos formas: internamente en el ORB (in-line), ya sea como servicios o como código de stubs y esqueletos, y como capas por encima del ORB (request-level). Transitoriamente, se puede empezar a utilizar un nuevo ORB que coexista con el antiguo.
Las referencias interoperables a objetos
Las referencias interoperables a objetos presentan las siguientes premisas: 1) No es necesario que los clientes sepan si las referencias de los objetos a los que dirigen peticiones son locales o remotas, ni si son del mismo ORB o de otro. 2) No es necesario que un ORB pueda tratar las referencias a objetos asignadas por otro ORB.
© Editorial UOC
297
Capítulo VII. Introducción al software...
Por lo tanto, en principio hay un dominio de referencias a objetos por cada ORB, y es necesario prever el puente correspondiente. También hace falta prever la conversión de códigos de caracteres. El protocolo interORB general (GIOP)
El protocolo interORB general sirve para la comunicación directa entre ORB, y está pensado para funcionar directamente sobre cualquier protocolo orientado a la conexión. Consta de los siguientes elementos: 1) La Common Data Representation (CDR), que es una sintaxis estándar que transforma tipos de datos de IDL en una representación de bajo nivel para la transferencia entre ORN o bien entre puentes interORB. 2) Un conjunto de formatos de mensajes que pueden ser de cliente, de servidor o mixtos, para facilitar las peticiones, localizar implementaciones de objetos (incluso cuando pueden emigrar dinámicamente) y gestionar canales de comunicaciones, además de soportar toda la funcionalidad de CORBA entre ORB. 3) Un conjunto de requisitos en lo que respecta al transporte: debe estar orientado a la conexión, debe garantizar que los bytes lleguen en el orden en que se han enviado y sin repeticiones, no debe haber límites en el tamaño del mensaje y no debe hacer falta fragmentación o alineación. El protocolo interORB de Internet (IIOP)
El protocolo interORB de Internet forma parte de la especificación del GIOP. Especifica cómo se pueden intercambiar mensajes de GIOP mediante TCP/IP, y también se puede utilizar como protocolo entre puentes intermediatos (“medios puentes”). Las definiciones del GIOP son abstractas, y el IIOP las convierte en concretas; de este modo, el IIOP describe el uso de las conexiones de TCP/ IP y cómo se identifican los objetos. Los protocolos interORB para entornos específicos (ESIOP)
CORBA prevé que haya protocolos para la interoperación con infraestructuras concretas preexistentes de red o de computación distribuida. Estas infraestructuras pueden soportar para los protocolos funciones específicas como la seguridad y la administración. Estos protocolos deberían cumplir las reglas ge-
© Editorial UOC
298
Ingeniería del software
nerales para la interoperabilidad. La versión 2.3 de CORBA incluye la especificación de un ESIOP para DCE, DCE Common Inter-ORB Protocol (DCE-CIOP).
4. RMI
RMI (Remote Method Invocation) es la herramienta de Java para el soporte de objetos distribuidos. RMI tiene una funcionalidad muy reducida en comparación con CORBA, pero en cambio presenta la ventaja de que las invocaciones remotas tienen lugar sin salir del entorno Java. Aquí no se verán las sentencias de Java que cumplen esta función, sino sólo sus aspectos generales. Las invocaciones remotas equivalen a las locales desde el punto de vista formal. Del mismo modo que en las locales, por lo tanto, el valor de un argumento o el resultado puede ser un objeto de cualquier clase; de esta manera, no sólo se pueden transmitir datos entre los objetos cliente y el servidor, sino también objetos completos e implementaciones de objetos que se pueden ejecutar una vez recibidas. Para pasar los objetos se utilizan los mecanismos estándar de serialización de Java. RMI se puede combinar con JNI para acceder a servidores programados en otros lenguajes, y con JDBC para acceder a bases de datos relacionales. Se pueden aplicar las funciones de seguridad y la comprobación de tipos de Java.
4.1. Mecanismos de una invocación remota
Es preciso definir las referencias para cada servidor que hay que exportar. Cuando un cliente recibe una referencia en un servidor RMI, obtiene un stub que da formato a los argumentos, utiliza la serialización y envía la invocación al servidor. Por la parte del servidor, RMI recibe la invocación y la conecta a un esqueleto que restituye el formato a los argumentos e invoca la implementación del método al servidor; una vez ejecutado el método, el esqueleto da formato al
© Editorial UOC
299
Capítulo VII. Introducción al software...
resultado –ya sea un valor o una excepción– y envía el valor al cliente o provoca la excepción. Tanto los stubs como los esqueletos se generan a partir de la implementación del servidor.
5. Documentos compuestos distribuidos: DCOM
A pesar de que se acostumbra a considerar que la manipulación de documentos pertenece más al dominio de la ofimática que al de la informática profesional, los documentos compuestos nos interesan por dos razones: 1) Porque dentro de una interfaz gráfica de usuario pueden figurar documentos, considerados objetos. 2) Porque los documentos compuestos pueden resultar de la combinación de documentos distribuidos, y la tecnología de documentos distribuidos es un caso particular de la tecnología de objetos distribuidos.
5.1. Concepto de documento compuesto
Los documentos son objetos que se presentan directamente al usuario de forma visual y/o auditiva. Los documentos compuestos son aquellos documentos que resultan de la agregación de otros (que también pueden ser compuestos), que denominaremos componentes, dentro de un determinado documento marco. Los objetos compuestos acostumbran a ser generados en tiempo de ejecución; por otro lado, diferentes objetos componentes pueden ser gestionados y presentados por aplicaciones distintas. Por lo tanto, la característica básica que debe tener una herramienta de gestión de documentos compuestos es un protocolo que permita la comunicación entre un conjunto lo bastante amplio de aplicaciones que gestionen tipos diferentes de documentos. La utilización de las aplicaciones diferentes en cuestión es mucho más cómoda para el usuario si se hace mediante
© Editorial UOC
300
Ingeniería del software
un documento compuesto que si se hace pasando de una aplicación a otra de la forma convencional: pasando de una ventana a otra, abriendo manualmente cada fichero, etc.
5.2. Aspectos de la gestión de los documentos compuestos
A continuación presentamos aspectos diferentes de la gestión de los documentos compuestos: a) Presentación: el documento marco se presenta dentro de una sola ventana; cualquier documento compuesto debe tener la apariencia de un documento único. La aplicación que se encarga de un documento compuesto gestiona los contenedores donde se ubican los documentos componentes y, en particular, comunica a las aplicaciones que los gestionan todos los acontecimientos que tienen que ver con el contenedor respectivo. Por ejemplo, si se redimensiona.
b) Almacenamiento estructurado: un documento simple se guarda en un fichero monolítico, mientras que un documento compuesto se guarda en uno que tiene partes que corresponden a los diferentes documentos componentes; la parte que corresponde a un documento puede contener, en efecto, el documento, o bien tener un puntero hacia el documento, que entonces reside en un fichero independiente. c) Scripts: son programas que se ejecutan cada vez que se produce un determinado acontecimiento, cuya función puede ser, por ejemplo, pedir una clave de acceso, dar acceso a más o menos partes del documento según la clave, acceder a un gestor de datos (data warehouse), etc. Es conveniente decir que los scripts se deben poder preparar de una forma que no requiera programación convencional, ya que generalmente los usuarios que crean los documentos no son programadores. Por ejemplo, cuando se lee o se graba un documento.
© Editorial UOC
301
Capítulo VII. Introducción al software...
d) Transferencia de datos uniforme: los documentos compuestos deben permitir el intercambio datos –principalmente documentos que incluyen documentos compuestos enteros– con aplicaciones exteriores. Por ejemplo, cut and paste, drag and drop, enlace mediante punteros, etc.
5.3. OLE, COM y DCOM
OLE es una ampliación del portapapeles y de DDE para crear documentos compuestos orientados a objetos. Dynamic Data Exchange (DDE) permite vincular un elemento componente a varios documentos compuestos, sin estar contenido en ninguno de éstos y de forma que se puede editar, en principio, tan directamente como en un documento compuesto.
La inclusión de documentos componentes se puede llevar a cabo de dos formas: • con embedding (inclusión), una copia del objeto y su formato de presentación se almacenan dentro del documento y se transfieren con éste; • con linking (enlace), el documento que se incluye dentro del compuesto continúa dentro de su ubicación original en un documento exterior o dentro del mismo documento compuesto, y el objeto que lo representa en este último sólo contiene el formato y un puntero. Evolución de la tecnología de integración de documentos La sigla OLE viene de Object Linking and Embedding. En 1990, Microsoft introdujo la tecnología OLE 1 como herramienta básica para integrar documentos creados por diferentes aplicaciones y datos multimedia en un documento marco; funcionaba sobre la base de que cuando una aplicación necesitaba un documento creado por otra, esta última aplicación se ponía en marcha en una ventana aparte. En 1993 apareció OLE 2, incorporaba como núcleo una tecnología de encapsulación de objetos denominada COM (Component Object Model); de este modo, OLE 2 ya no era sólo una herramienta para gestionar documentos compuestos, sino también una arquitectura para objetos bastante más general. En 1994 se le añadió un concepto
© Editorial UOC
302
Ingeniería del software
nuevo, el OCX, que fue un componente genérico que se incluye dentro del documento marco. Sin embargo, ya no hubo un OLE 3: desde entonces las versiones nuevas de OLE simplemente forman parte de las versiones nuevas de Windows. Posteriormente, ha aparecido DCOM (Distributed Component Object Model); DCOM extiende COM a entornos LAN, WAN e incluso a Internet. COM y DCOM han pasado de Microsoft al consorcio ActiveX, y DCOM está disponible para Windows NT 4.0 y Windows 2000, así como para Windows 95 y 98. Además, Software AG ha hecho implementaciones de ello para diversas plataformas Unix: Solaris, Linux y HP/UX. Sin embargo, la estrategia de Microsoft no es que Windows funcione necesariamente con OLE, sino que la interfaz de usuario de Windows pueda estar soportada también por productos como Taligent y OpenStep.
5.3.1. Arquitectura
El Component Object Model (COM) es algo parecido a un ORB para un único ordenador; DCOM soporta la distribución. Dentro de la arquitectura podemos encontrar el grupo de los siguientes elementos: objetos, clases, interfaces y servidores. 1) Se denominan componentes los objetos de OLE, es decir, los documentos que se pueden incorporar a un documento complejo. Un objeto de COM no es un objeto clásico: es sólo un grupo de funciones (denominadas también métodos o funciones de miembros) relacionadas, pero que no tienen estado ni identidad, y un cliente no puede volver a conectar con el mismo objeto, sino sólo con un puntero de interfaz de la misma clase. En estos subapartados, los términos objeto, componente y documento se utilizarán indistintamente. Un documento compuesto es el resultado de la interacción entre contenedores y servidores; se podría decir que los contenedores son lugares y los servidores son cosas que se ponen en estos lugares. Atención Aquí, el significado del término servidor no es el mismo que cuando se habla de cliente/ servidor; sin embargo, los contenedores se pueden considerar clientes de los servidores
© Editorial UOC
303
Capítulo VII. Introducción al software...
2) Las clases que implementan una interfaz o más tienen un identificador único que se denomina CLSID; un objeto es una implementación en tiempo de ejecución de una clase. Un componente consta de una clase que implementa una interfaz o más y una factoría de clase que instancia un objeto de la clase. 3) OLE y COM especifican interfaces entre objetos componentes dentro de una aplicación o entre aplicaciones, y proporcionan una API para la localización dinámica de interfaces y para cargarlas y ejecutarlas. Un componente puede tener una interfaz o más. Hay interfaces del mismo OLE e interfaces de usuario. Para definir estas interfaces, Microsoft tiene dos lenguajes: Interface Definition Language (IDL) y Object Description Language (ODL), que lo contiene. El lenguaje ODL para la definición de interfaces es un lenguaje textual que se puede codificar manualmente o bien se puede generar mediante Visual C++ de Microsoft. Las interfaces de COM no generan código en lenguajes de programación, como las de CORBA, sino únicamente una API en binario para acceder a las interfaces mediante punteros. Se depositan en una biblioteca de tipo (type library), que tiene un papel similar al del depósito de interfaces de CORBA. Las interfaces tienen nombres que deben empezar por I, pero en tiempo de ejecución se identifican por un identificador de interfaz (IID), que es generado por COM y no repetido, y que también identifica al objeto. Todas las interfaces de COM derivan de la interfaz IUnknown. Las interfaces del usuario constan de métodos con sus parámetros, se crean en IDL y se les aplica el compilador de MDL; de esta compilación se obtienen servidores intermediarios (proxies) del cliente, stubs del servidor y el código que hace corresponder los parámetros de unos y otros. Todo esto tiene lugar en C. Los proxies (servidores intermediarios) y los stubs se utilizan cuando el cliente y el objeto llamado están en diferentes procesos.
Encontramos tanto la invocación estática de interfaces como la dinámica, que puede utilizar una biblioteca de tipo, donde hay descripciones de objetos en ODL precompiladas, con sus interfaces y parámetros. 4) Un servidor es un fichero .dll o .exe que contiene una clase o más; cuando un cliente pide un objeto de un determinado CLSID, COM pide al servidor crear un objeto de aquella clase, y por este motivo el servidor debe proporcionar la
© Editorial UOC
304
Ingeniería del software
factoría de clase; cuando se crea un objeto, el servidor retorna el IID de la interfaz primaria. La herencia
No hay referencia múltiple, pero se suple sobre la base de que los objetos pueden soportar varias interfaces. Esto permite crear objetos que presenten a los clientes los servicios de los objetos que agrupan (es decir, que los encapsulen), efecto que se puede conseguir mediante dos métodos: • Contención y delegación: el objeto “contenedor” envía a los objetos internos las invocaciones de los respectivos métodos que recibe de los clientes. • Agregación: la interfaz de cada objeto interno forma parte de la del objeto “contenedor” y, por lo tanto, los clientes se pueden dirigir directamente a los objetos internos. Acontecimientos
En COM, el soporte de los acontecimientos se hace por medio de los objetos o las fuentes conectables, que soportan interfaces de salida (además de las de entrada); cada función de una de estas interfaces corresponde a un tipo de acontecimiento COM que proporciona interfaces, denominadas sumideros, para que otros objetos se puedan suscribir a los acontecimientos que las fuentes envían codificados en ODL; no hay nada parecido en los canales de acontecimientos de CORBA.
5.3.2. Los documentos compuestos y los OCX
Un documento compuesto de OLE contiene tantos datos propios como objetos gestionados por otras aplicaciones; típicamente le corresponde un fichero compuesto, y hace de intermediario entre dos tipos de componentes: los contenedores, que proporcionan lugares donde poner las cosas, y los servidores, que son las cosas que se ponen. Un tercer tipo de componentes de OLE son los OCX, que tienen un conjunto de interfaces predefinidas. Un contenedor es una aplicación de OLE que contiene un documento compuesto (o bien físicamente o bien sólo un puntero en este documento, en forma
© Editorial UOC
305
Capítulo VII. Introducción al software...
de moniker del servidor o los servidores del objeto). Para cada servidor, el contenedor crea un lugar donde actuará el servidor y presentará su contenido. Clasificación de los contenedores y servidores
Los contenedores pueden ser puros (que sólo soporten embedding), y linked (que sólo soporten linking). La clasificación de los servidores es la siguiente: a) In-process: se implementan en forma de DLL en el mismo espacio de direcciones que el contenedor, y sólo pueden tratar objetos embedded; se subdividen en los siguientes: • InProcHandlers, en los que varios servidores pueden compartir una misma ventana y menús relativos a un documento. • InProcServers, DLL locales utilizadas por los servidores locales. • Controls. b) Locales, que se implementan en forma de ficheros .exe separados, se comunican por Lightweight RPC con los contenedores y se ejecutan en la misma máquina y el mismo sistema operativo que sus clientes. Una clasificación de los servidores por función es la siguiente: • full servers, que soportan tanto embedding como linking y son aplicaciones autónomas, como Excel y Word; • miniservers, que sólo soportan embedding y sólo pueden funcionar en la aplicación del contenedor, como ocurre en el caso de Graph de Microsoft. c) Remotos, que se comunican por medio de RPC ordinarias con los contenedores. Los OCX
Un OCX es una combinación de un servidor in-process y un servidor de automatización, y soporta embedding, edición in-place, automatización, notificaciones y, además, objetos conectables, licencias y edición de propiedades. Los contenedores para los OCX son contenedores para objetos embedded y edición in-place que, además, tienen unas propiedades de entorno accesibles al
© Editorial UOC
306
Ingeniería del software
OCX y unas propiedades extendidas que gestionan para éste (aparte de las propiedades que gestiona el mismo OCX, que son las propiedades de control). Propiedades como por ejemplo el color del fondo, el tamaño del tipo de letra, etc.
5.3.3. La transferencia de datos
Lo que se transfiere –mediante un protocolo de transferencia de OLE– son objetos de datos, cuyo contenido puede estar representado en tres formatos diferentes: 1) estándar, que comprende los formatos utilizados en el portapapeles de Windows; 2) privados, que son específicos de las aplicaciones; 3) de OLE, que pueden tener dos estructuras diferentes: a) FORMATETC, que contiene una descripción del tipo de datos, el dispositivo de almacenamiento y un puntero en los datos. b) STGMEDIUM, que describe el medio utilizado para transferir los datos (memoria, disco u objetos de documentos compuestos de OLE), y un puntero en la variable que se utiliza para hacerlo. Existen tres protocolos para la transferencia de datos: recortar/copiar y pegar por medio del portapapeles, drag and drop y mediante enlaces. Transferencia de datos mediante enlaces El enlace entre documentos incluye un mecanismo de actualización automática de todas las copias del documento por “publicación y suscripción”: se crea un objeto con una copia de los datos, que se deposita dentro de un directorio al que tienen acceso los suscriptores y que también contiene los enlaces a éstos. Dentro de cada documento suscriptor hay un objeto que contiene la copia (que es único incluso cuando la copia se utiliza en más de un lugar del documento); cuando se modifica el documento, se envía una notificación a todos los suscriptores, que entonces pueden pedir una copia actualizada.
© Editorial UOC
307
Capítulo VII. Introducción al software...
5.3.4. El almacenamiento estructurado y los monikers OLE tiene la arquitectura estructurada de almacenamiento que permite guardar en un solo fichero compuesto varios documentos independientes entre sí. Los servicios de persistencia y almacenamiento estructurado de OLE utilizan tres tipos de elementos: 1) Los ficheros compuestos u objetos de almacenamiento constituyen una jerarquía de ficheros implementada en forma de elementos de directorio denominados almacenamientos, y de un tipo de ficheros denominados streams, que contienen una porción de datos más un puntero para acceder a éstos. Entre los almacenamientos, encontramos hay uno que es la raíz del fichero compuesto, que tiene una función para asociar el objeto de almacenamiento a un fichero de los gestionados por el sistema operativo. Un objeto de almacenamiento no contiene datos de la aplicación, pero sí nombres de almacenamientos y de streams. 2) Los objetos persistentes son objetos que se pueden leer o grabar en sí mismos. Los objetos pueden soportar interfaces diferentes -una o más al mismo tiempo- que les dan niveles distintos de persistencia. 3) Los monikers son objetos que actúan como alias persistentes de otros; por ejemplo, ficheros, consultas a bases de datos, párrafos de documentos, etc. Además, hay definidas distintas clases aplicables a diferentes tipos de objetos: de ficheros, de ítems (fragmentos de documentos), anti (que anulan un moniker anterior), de punteros en memoria, y compuestos (que incluyen otros monikers, incluso compuestos). DCOM también utiliza monikers de URL, para los protocolos HTTP, HTTPS, FTP y GOPHER, que permiten acceder a objetos persistentes en Internet.
5.3.5. Los scripts y las librerías de tipos Los programas clientes pueden invocar métodos que manipulan objetos con scripts. Para ello hay tres clases de componentes: 1) Servidores de automatización, que son los objetos a los que da acceso una aplicación con scripts. Puede haber más de uno por aplicación. Tienen métodos, que son funciones de miembros, y propiedades, cada una de las cuales es un par de funciones de miembros: una que pone un valor y otra que lo lee.
© Editorial UOC
308
Ingeniería del software
2) Controladores de automatización, que son las herramientas y los programas de los clientes que acceden al servidor de automatización. Visual Basic, a partir de la versión 3.0, es un controlador de automatización. 3) Una librería de tipos describe los métodos de entrada y de salida y las propiedades de un servidor. 4) Un solo programa puede controlar servidores de automatización de varias aplicaciones.
5.3.6. La interoperabilidad entre CORBA y COM/DCOM
La interoperabilidad entre CORBA y COM/DCOM pretende permitir el acceso de un cliente CORBA a un servidor DCOM, y al revés. Las especificaciones de CORBA describen las correspondencias entre diferentes elementos de CORBA y de COM: tipos de datos, identificadores de interfaces, excepciones, operaciones, atributos y herencia para que se puedan automatizar.
6. Desarrollo del software distribuido
6.1. El análisis de requisitos en el caso de software distribuido El análisis de requisitos en el caso de software distribuido es independiente del hecho de que el software que se derive de éste sea distribuido o no; la razón es que este análisis se ocupa de lo que le debe aparecer al usuario por las pantallas y por las impresoras, independientemente de que todo el proceso se haga localmente o no.
6.2. La distribución de los objetos En el caso de software distribuido, el diseño es igual que en el caso general, a excepción de que tiene un paso más al final: la distribución de los objetos; las cla-
© Editorial UOC
309
Capítulo VII. Introducción al software...
ses y los objetos que tenga el software, independientemente de que deba estar distribuido o no, son los mismos porque están determinados por la funcionalidad.
6.2.1. Uso del diagrama de despliegue
En el caso de que el diseño se haga orientado a objetos y con UML, está claro que el diagrama de despliegue se presta muy bien a describir la distribución de objetos entre los nodos. De hecho, sin embargo, lo que se distribuirá no serán objetos y clases individuales, sino componentes más complejos.
6.2.2. Distribución de los diferentes tipos de clases de análisis
Una forma sencilla de distribuir los objetos consiste en partir de la distinción entre clases de frontera, de entidades y de control; podemos establecer estas reglas orientativas: a) Las clases de frontera se deben ubicar en las máquinas en que trabajan los usuarios directamente. b) Las clases de entidades y los respectivos gestores de disco estarán normalmente en las máquinas servidoras que tienen las bases de datos. c) Las clases de control se colocarán justo con las de frontera o bien con las de entidades, según tengan más interacción con unas u otras.
6.2.3. Un paradigma alternativo
Scott Ambler, basándose en técnicas de Rebecca Wirfs-Brock y otros autores, propone una técnica para la distribución de los objetos en arquitecturas cliente/servidor de n capas sin agentes móviles. Distingue cinco tipos de clases: • Clases de la interfaz con el usuario. • Clases del negocio/dominio.
© Editorial UOC
310
Ingeniería del software
• Clases de proceso, que implementan procesos que afectan a varias clases del dominio. • Clases de persistencia, que pueden ser gestores de disco o frameworks. • Clases del sistema, como por ejemplo las de comunicación entre procesos. La distribución de los objetos se haría en nueve pasos: 1) Distribución de las demás clases antes que las del negocio/dominio. Las clases de la interfaz con el usuario se asignarían sistemáticamente a los clientes, y las de persistencia, a los nodos donde debe estar la base de datos, si es única, y en caso de que no lo sea, en un nodo aparte. Las clases del sistema que corresponden a servicios de uso general se replicarían en todos los nodos, mientras que las de servicios más específicos se pondrían en un nodo aparte. Por ejemplo, seguridad.
2) Definir el contrato (interfaz pública) de las clases. 3) Simplificar las jerarquías de especialización y agregación. Si una subclase no tiene contrato propio, irá donde vaya la superclase; un componente por composición irá con la clase compuesta. 4) Identificar los componentes potenciales del dominio. Un componente es un conjunto de clases que colaboran para ofrecer un conjunto de contratos que sea coherente visto desde el exterior. Se supone que hay mucha más circulación de información entre las clases de un componente que entre el componente y el exterior. Una clase servidora con varios clientes probablemente tendrá que ser un componente aparte, igual que aquellas clases que son sólo clientes; sin embargo, si una clase servidora tiene un solo cliente, se pueden poner o bien juntas o bien en máquinas diferentes, unidas por una conexión de alta velocidad. Dos clases que colaboren con frecuencia irán dentro del mismo componente. 5) Definir los contratos en lo que respecta a componente del dominio. Si todo el contrato de una clase servidora está incluido dentro del contrato de componente al que pertenece, probablemente será mejor segregarla como componente aparte; en cambio, si ninguna operación del contrato de una clase forma parte del contrato del componente al que pertenece, entonces debe constituir un subsistema interno del componente.
© Editorial UOC
311
Capítulo VII. Introducción al software...
6) Simplificar los contratos de los componentes, agrupando operaciones con vistas a reducir el número de tipos de mensaje diferentes. 7) Asignar componentes a nodos mediante el diagrama de despliegue. Será necesario buscar la minimización del tráfico por la red. La distribución se tendrá que probar, y si es necesario, se deberá cambiar. 8) Añadir clases complementarias, como por ejemplo clases que actúan como interfaz de los componentes. 9) Distribuir las clases de la interfaz con el usuario según los casos de uso que tendrán lugar en cada nodo.
© Editorial UOC
312
Ingeniería del software
Bibliografía
Bibliografía básica Booch, G.; Rumbaugh, J.; Jacobson, I. (1999). El lenguaje unificado de modelado. Madrid: Addison-Wesley. Booch, G.; Rumbaugh, J.; Jacobson, I. (1999). UML. El lenguaje de modelado unificado. Guía del usuario. Addison Wesley. Buschmann, F.; Meunier, R.; Rohnert, H.; Sommerlad, P.; Stal, M. (1996). A System of Patterns. Pattern-Oriented Software Architecture. Addison-Wesley. Coplien, J.O.; Schmidt, D.C.; Vlissides, J.M.; Kerth, N. (1996). Pattern Languages of Program Design 2. Addison-Wesley. Eriksson, H.E.; Penker, M. (1997). UML Toolkit. John Wiley & Sons. Fowler, M.; Scott, K. (1997). UML Distilled. Reading: Addison-Wesley Longman. Fowler, M.; Scott, K. (1999). UML gota a gota. Amsterdam: Prentice Hall. Gamma, E.; Helm, R.; Johnson, R.; Vlissides, J. (1995). Design Patterns: Elements of Reusable Object Oriented Software. Reading: Addison-Wesley. Gerarthy, R. y otros (1999). DCOM-CORBA Interoperability. Prentice Hall. Harrison, N.; Foote, B.; Rohnert, H. (1999). Pattern Languages of Program Design 4. Addison-Wesley. Jacobson, I. (1994). Object-Oriented Software Engineering: A Use Case Driven Approach. Addison- Wesley. Jacobson, I.; Booch, G.; Rumbaugh, J. (2000). El proceso unificado de desarrollo de software. Addison-Wesley. Kruchten, P. (2000). The Rational Unified Process. An Introduction (2.ª ed.). Addison-Wesley. Larman, C. (1998). Applying UML and Patterns. An Introduction to Object-Oriented Analysis and Design. Upper Saddle River: Prentice-Hall. Martin, R.C.; Riehle, D.; Buschmann, F.; Vlissides, J.M. (1997). Pattern Languages of Program Design 3 (Software Patterns Series). Addison-Wesley. Meyer, B. (1997). Object-Oriented Software Construction (2.ª ed.). Upper Saddle River: Prentice-Hall. Meyer, B. (1999). Construcción de software orientado a objetos (2.ª ed.). Madrid: Prentice-Hall. Orfali, R.; Harkey, D.; Edwards, J. (1999). Client/Server Survival Guide (3.ª ed.). Nueva York: John Wiley & Sons. Pressman, R.S. (1997). Ingeniería del software. Un enfoque práctico (4.ª ed.). Madrid: McGraw-Hill. Richter, Ch. (1999). Designing Flexible Object-Oriented Systems with UML. Indianápolis: MacMillan.
© Editorial UOC
313
Bibliografía
Rock-Evans, R. (1998). DCOM Explained. Digital Press. Rosenberg, D.; Scott, K. (1999). Use Case Driven Object Modeling with UML: A Practical Approach. Reading: Addison-Wesley. Rumbaugh, J.; Jacobson, I.; Booch, G. (2000). UML. El lenguaje de modelado unificado. Manual de referencia. Madrid: Addison-Wesley. Slama, D.; Garbis, J.; Russell, P. (1999). Enterprise CORBA. Prentice Hall. Sommerville, I. (1995). Software Engineering (5.ª ed.). Harlow: Addison-Wesley. Weinschenk, S.; Jamar, P.; Yeo, S.C. (1997). GUI Design Essentials. John Wiley & Sons.
© Editorial UOC
314
Ingeniería del software
Glosario
acción f Proceso que o no se ejecuta o se ejecuta hasta el final. acontecimiento m Hecho que se produce en un instante en el tiempo y que puede provocar una transición. activación f Parte de la línea de vida de un papel de clasificador durante la cual se ejecutan acciones vinculadas al mismo. actor m Conjunto de papeles de una entidad exterior en relación con el sistema del software considerado. arquitectura cliente/servidor m Sistema distribuido en el que un programa, el servidor, gestiona un recurso compartido; en relación con este recurso, otros programas y los clientes pueden pedir funciones determinadas. asociación binaria f Aquélla en la cual participan sólo dos clases. asociación derivada f Asociación redundante que resulta de la combinación de otras relaciones. asociación reflexiva f Asociación binaria de una clase consigo misma. atributo de clase m Atributo que tiene un único valor para toda la clase. atributo derivado m Atributo cuyo valor se puede obtener a partir del de otros atributos. cardinalidad m En una asociación binaria, la cardinalidad de un papel A es el número de objetos del otro papel B al que puede estar enlazado cada objeto de A; se indica el valor máximo y mínimo de este número. En una asociación ternaria es lo siguiente: la cardinalidad del papel A expresa los límites al número de objetos de A que pueden estar enlazados en cada combinación concreta de un objeto del papel B y uno del papel C. CASE sigla de Computer-Aided Software Engineering. caso de uso m Interacción entre el software y un actor o más que comporta una o más acciones. ciclo de vida clásico m Ciclo de vida en el que se supone que cada etapa se basa en los productos de la anterior y no se vuelve nunca a etapas anteriores. sin: ciclo de vida en cascada.
© Editorial UOC
315
Glosario
ciclo de vida en cascada m sin: ciclo de vida clásico. ciclo de vida iterativo e incremental m Todo ciclo de vida en el que se pasa de manera repetida por las mismas fases desarrollando cada vez un fragmento más de software. ciclo de vida m Conjunto de etapas del desarrollo de software por las cuales se pasa en el orden previamente establecido. clase abstracta f Superclase de la cual no se pueden instanciar objetos porque cada uno de sus objetos debe pertenecer a alguna de sus subclases. clase asociativa f Asociación que, por el mero hecho de tener atributos y/o operaciones propias, llega a ser una clase. clase de control f Clase no persistente que implementa todos los algoritmos principales de un caso de uso o parte de ellos. clase de entidades f Clase del dominio del software. clase de frontera f Clase que implementa una parte de la interfaz de usuario en el ámbito de análisis. clase de utilidad f Recurso para agrupar procesos y/o datos en forma de una clase que no puede tener objetos. clase diferida f Clase abstracta que tiene alguna operación abstracta. sin.: clase virtual. clase parametrizada f Especificación de una clase en la cual permanecen sin concretar algunos aspectos de sus operaciones o atributos en forma de parámetros a los que se debe dar un valor. sin.: plantilla. clase persistente f Clase que puede tener objetos que se deban hacer persistentes. clase temporal f Clase que no es persistente, es decir, cuyos objetos no se pueden hacer persistentes. clase terminal f Clase cuyas subclases no se permite que se definan. clase virtual f Ved clase diferida. clase f Conjunto de objetos que tienen los mismos atributos y operaciones. clasificador: Concepto que comprende las clases, las interfaces y los tipos de datos.
© Editorial UOC
316
Ingeniería del software
COM véase Component Object Model. Common Object Request Broker Architecture: Especificaciones de un middleware para objetos distribuidos elaborado por la OMG con el fin de que se convierta en un estándar. sigla: CORBA Component Object Model: Herramienta de gestión de objetos que se encarga de la gestión de documentos de OLE. sigla: COM componente m Conjunto de clases que colaboran para llevar a cabo una función concreta. Exteriormente se ve como una clase que implementa una interfaz determinada. componente m Objeto físico que existe en tiempo de desarrollo, de compilación o de ejecución y que tiene identidad propia e interfaz. Computer-Aided Software: véase CASE. contexto (del software) m Entorno en el cual se utilizará el software que hay que desarrollar; nos interesa especialmente la organización y la terminología. CORBA: véase Common Object Request Broker Architecture Custom Control: sin.: OCX desarrollo de software orientado a objetos m Desarrollo de software con métodos centrados en el concepto de objeto derivados de la programación orientada a objetos. desarrollo estructurado de software m Desarrollo de software con métodos derivados de la programación estructurada e históricamente anteriores a los orientados a objetos. diagrama estático de análisis m Diagrama estático obtenido durante la etapa de análisis que comprende las clases de entidades, de control y de frontera con sus atributos, operaciones y relaciones. dominio m Porción del mundo real considerada por una aplicación. especialización f Identificación de una o más subclases dentro de una clase. esqueleto m Correspondencia entre las operaciones de una interfaz y los métodos de los sirvientes que la implementan. Depende del ORB (es decir, su formato no es estándar) y del lenguaje de programación. Se obtiene al compilar la interfaz.
© Editorial UOC
317
Glosario
estado de acción m Estado que corresponde al hecho de que se encuentre en curso una acción determinada. estado de un objeto mv Conjunto de los valores de los atributos de un objeto en un momento dado. estado persistente de un objeto m Estado del objeto que está grabado en un sistema de almacenamiento permanente. Puede ser sólo una parte del estado del objeto, y en un momento dado puede ser diferente del estado del objeto en memoria. estado m Situación durante la vida de un objeto o la duración de una interacción en la cual cumple alguna condición, lleva a cabo alguna actividad o espera algún acontecimiento. estereotipo m Variante de un elemento del UML. Hay estereotipos estándares, definidos dentro del UML, y se pueden definir como específicos para un proyecto. Los estereotipos se identifican por una palabra clave entre « ». estímulo m Petición de una operación o comunicación de una señal que llega a un objeto. framework véase marco. general InterORB Protocol Protocolo general para la comunicación directa entre ORB. sigla: GIOP generalización f Definición de una superclase por abstracción de los atributos y operaciones comunes en di-ferentes clases, que pasan a ser sus subclases. GIOP véase General InterORB Protocol herencia f Característica por la cual todas las subclases tienen al menos todos los atributos y operaciones de cada una de sus superclases. herramientas CASE fs Software de apoyo al desarrollo, mantenimiento y documentación informatizados de software. IIOP véase Internet InterORB Protocol. ingeniería del software f Conjunto de las técnicas, métodos y herramientas que se utilizan para producir software. instancia f Un objeto es una instancia de su clase. Este concepto se extiende a los clasificadores.
© Editorial UOC
318
Ingeniería del software
interacción f Especificación del funcionamiento de una operación o caso de uso en términos de secuencias de mensajes entre instancias de clasificadores que piden operaciones o envían señales. interfaz de usuario f Lo que ven los usuarios del funcionamiento del software. Interfaz: Conjunto de operaciones de una clase visibles desde otras clases. Internet InterORB Protocol: Forma concreta que toma el GIOP en el caso de que la conexión entre ORB se haga mediante el protocolo de Internet, TCP/IP. invocación dinámica f Invocación de una demanda que se construye justo antes de ser invocada, en tiempo de ejecución. línea de vida f Intervalo de tiempo durante el cual existe un papel. marco: Conjunto de clases que constituye una aplicación genérica e incompleta que hay que complementar con clases del usuario. Sin.: framework. métodos formales de desarrollo de software m pl Métodos de desarrollo que se basan en la especificación de los requisitos en términos de un formalismo matemático riguroso. middleware Software que cumple el papel de intermediario entre múltiples clientes y múltiples servidores. modelo estático m Modelo que describe las propiedades permanentes del software en términos de clases y objetos. nodo m Representación de un objeto físico existente en tiempo de ejecución con memoria y capacidad de proceso. object Linking and Embedding: Herramienta de Microsoft para integrar dentro de un documento marco documentos gestionados por diferentes aplicaciones y datos multimedia. sigla: OLE object Management Group véase OMG. object Request Broker Pseudoobjeto que constituye aquella parte de CORBA que se encarga de transmitir las peticiones de los objetos clientes a los objetos servidores. sigla: ORB
© Editorial UOC
319
Glosario
objeto persistente m Objeto que no se debe destruir cuando acaba el proceso que lo ha creado porque lo tiene que utilizar algún proceso posterior. Hay que grabar su estado en un fichero permanente o base de datos. OCX: Combinación de un servidor in-process y uno de automatización. Como fichero tiene la extensión .ocx. sin.: Custom Control OLE véase Object Linking and Embedding OMG Organización no lucrativa de empresas productoras y consumidoras de bienes y servicios informáticos que tiene la finalidad de fomentar el uso de la tecnología de objetos, y el medio con el que intenta conseguirlo es la elaboración de estándares. operación abstracta: Operación de una superclase que no está implementada en ésta sino sólo en sus subclases. ORB véase Object Request Broker paquete m Elemento del modelo que puede contener elementos de cualquier tipo, incluso paquetes. Sirve para fraccionar el modelo según algún criterio. patrón m Idea de diseño ampliamente probada y documentada. petición f Mensaje dentro de CORBA de un objeto cliente a un objeto servidor, para pedir la ejecución de una operación contenida en una superficie soportada por este objeto servidor. plantilla f véase clase parametrizada. poa véase Portable Object Adapter Portable Object Adapter Componente de CORBA, en el lado del servidor, que se encarga de transmitir las demandas recibidas del ORB a los sirvientes que implementan los objetos servidores a los que están dirigidas. sigla: POA prototipo: El prototipo de un sistema de software es una versión provisional del sistema, que sólo tiene lo imprescindible para que el usuario pueda comprobar si se han entendido bien sus requisitos. Remote Method Invocation: Parte de JAVA que soporta la invocación de operaciones entre objetos distribuidos. sigla: RMI
© Editorial UOC
320
Ingeniería del software
Requisitos m pl Descripción del comportamiento, propiedades y restricciones del software. RMI véase Remote Method Invocation señal f Estímulo entre dos instancias de clasificadores que puede provocar un acontecimiento. sirviente: En CORBA, implementación de una interfaz a la que el POA correspondiente puede encargar la ejecución de una demanda dentro del servidor. sistema abierto m Sistema distribuido basado en un conjunto de normas ampliamente aceptadas en el ámbito internacional. transición compuesta f Transición con varios estados de origen y/o de destino. transición interna: Recurso para especificar que cuando se produce un determinado acontecimiento que tiene lugar mientras el objeto está en un cierto estado, se deben ejecutar determinadas acciones sin que se produzca cambio de estado. transición simple f Paso de un estado de origen a otro de destino provocado por un acontecimiento. Puede poner en funcionamiento acciones. UML: Modelo estándar para la construcción de software orientado a objetos. sigla: Unified Modeling Language. Unified Modeling Lenguage véase UML. visibilidad f Propiedad de diferentes elementos del modelo que representa que son reconocidos en un ámbito más o menos grande externo a aquél en el cual se han definido.