Libro Completo UML

Roberto Cortés Morales INGENIERÍA DE SOFTWARE EFICAZ: LA PERSPECTIVA DE PROCESO UNIFICADO A TRAVÉS DEL ANÁLISIS ORIENTA

Views 88 Downloads 5 File size 2MB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Roberto Cortés Morales

INGENIERÍA DE SOFTWARE EFICAZ: LA PERSPECTIVA DE PROCESO UNIFICADO A TRAVÉS DEL ANÁLISIS ORIENTADO A OBJETOS, USANDO UML VERSIÓN PRELIMINAR

2008

Editora académica y asesora pedagógica: Stella Delolme Nossa Encargada de cátedra: Grethel Mena Araya

Este texto ha sido confeccionado por la UNED para ser utilizado en la asignatura Herramientas de Producción Avanzada, código 830 que se imparte en las carreras de Informática Administrativa y Técnico en Computación e Informática. Este material está dirigido a estudiantes de nivel avanzado en Análisis y Diseño de Sistemas Orientado a objetos.

2

TABLA DE CONTENIDO INTRODUCCIÓN

9

CAPÍTULO 1. GENERALIDADES SOBRE EL PARADIGMA DE ORIENTACIÓN A OBJETOS, EL PROCESO UNIFICADO Y CASOS DE USO OBJETIVOS PARADIGMA DE ORIENTACIÓN A OBJETOS Pensar en “objetos”: la abstracción del paradigma La clasificación: una descripción general de los objetos La Herencia: generalizar y especificar soluciones Distintas formas de hacer cosas parecidas: el polimorfismo

15 16 17 17 18 19 21

EL PROCESO UNIFICADO ¿Qué es el Proceso Unificado (UP)? El UP es orientado a casos de uso: historias del sistema El UP se centra en la arquitectura: dar sustento a los casos de uso El UP es iterativo e incremental: la convergencia a una solución UML y el UP

24 24 25 30 33 40

CASOS DE USO: LA GUÍA DEL PROCESO Cómo identificar los casos de uso de un sistema Los actores del sistema Casos de uso: cómo se visualizan Relaciones entre casos de uso Especificación básica de casos de uso Especificación detallada de casos de uso Elementos de una especificación detallada

40 41 43 43 46 46 49 50

CAPÍTULO 2.

EL MODELO CONCEPTUAL DE CLASES: LA EXPRESIÓN DE LOS CONCEPTOS DEL PROBLEMA

59

OBJETIVOS CONSIDERACIONES PRELIMINARES

60 61

DEFINICIÓN DEL MODELO CONCEPTUAL Modelando los conceptos Categorías de clases conceptuales

61 63 67

CASOS DE USO E IDENTIFICACIÓN DE CLASES CONCEPTUALES

68

3

DIFERENCIAR CONCEPTOS QUE SON CLASES Y CONCEPTOS QUE SON ATRIBUTO RELACIONES CONCEPTUALES ENTRE CLASES Cardinalidad de las relaciones Nombre de las relaciones Relaciones múltiples entre clases Relaciones hacia la misma clase Especificación de conceptos en el modelo de clases

71 73 74 77 82 83 83

AÑADIENDO ATRIBUTOS AL MODELO CONCEPTUAL

90

DEFINIENDO OPERACIONES EN EL MODELO

99

CAPÍTULO 3. DE CARA A LA IMPLEMENTACIÓN: EL MODELO DE CLASES DE DISEÑO OBJETIVOS CONSIDERACIONES PRELIMINARES

107 108 109

LA TRANSICIÓN DEL ANÁLISIS AL DISEÑO: LA VENTAJA DEL A/DOO

109

TARJETAS CRC: DOCUMENTAR Y EVALUAR LAS CLASES CONCEPTUALES

112

LAS CLASES DE DISEÑO DEL NEGOCIO Refinamiento en la definición de atributos y operaciones Constructores Tipo de datos de los atributos Tipos de retorno y parámetros de las operaciones Relaciones de asociación y de composición: las relaciones conceptuales vistas en la óptica del diseño Diferencia entre relaciones de asociación y de composición Apuntes sobre la jerarquía de herencia

114 114 116 119 121

LOS GESTORES: ¿QUIÉN DIRIGE LA ORQUESTA? Arquitectura en n-capas Definir clases de gestión

138 138 141

CAPÍTULO 4. EL MODELO DE INTERACCIÓN Y LA ARQUITECTURA DEL SISTEMA OBJETIVOS CONSIDERACIONES PRELIMINARES

145 146 147

DIAGRAMAS DE SECUENCIA: UN PRIMER ACERCAMIENTO Y SU UTILIDAD PARA DESCUBRIR LAS CLASES DE LA CAPA DE INTERFAZ Diagramas de secuencia de sistema Diagramas de secuencia: identificando la capa de interface

148 148 152

4

124 131 134

Interacción entre capas: añadiendo la capa de gestión Cajas de activación y su efecto en las operacionenes Visión del trabajo de los gestores en un diagrama de secuencia

154 155 158

DIAGRAMAS DE ACTIVIDAD: APOYANDO LA ESPECIFICACIÓN DEL DISEÑO Elementos de un diagrama de actividad Especificación de casos de uso y diagramas de actividad Especificación de operaciones

166 167 169 177

DIAGRAMAS DE ESTADOS Elementos de un diagrama de estados Elaboración de un diagrama de estados

179 179 181

CAPÍTULO 5. DE CARA A LA IMPLEMENTACIÓN

187

OBJETIVOS

188

CONSIDERACIONES PRELIMINARES

189

LAS PRUEBAS EN LA INGENIERÍA DEL SOFTWARE De lo particular a lo integral Pruebas de unidad Pruebas de integración y componentes

190 192 194 197

DESPLEGANDO LA SOLUCIÓN Elementos de un diagrama de despliegue Construyendo un diagrama de despliegue

206 208 208

COMPLETANDO EL PROCESO DE TRANSICIÓN

213

CONCLUSIONES

215

BIBLIOGRAFÍA

220

5

ÍNDICE DE FIGURAS 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28.

29. 30. 31.

La Clase Pelota Clase para cada tipo de cliente Superclase de cliente y clases derivadas por tipo de cliente Diagrama de casos de uso parcial de sistema de cajero automático La conceptualización del UP Un diagrama de casos de uso Diagrama de casos de uso para la administración de préstamos de la biblioteca universitaria Conceptos en un punto de venta de un supermercado Relaciones en el modelo conceptual Conceptos del Sistema de Préstamo Bibliotecario Diferencia entre clases conceptuales y atributos Definición de primeras relaciones entre clases conceptuales para el

Sistema de Préstamo Bibliotecario

Modelo de clases conceptuales para el Sistema de Préstamo Bibliotecario Modelo conceptual completo para el Sistema de Préstamo Bibliotecario Diferencias entre el diagrama del modelo conceptual inicial y el actual del Sistema de Préstamo Bibliotecario Visualización de las clases conceptuales y sus atributos Incorporación del caso de uso de Pagar Préstamos Morosos al modelo conceptual de clases del Sistema de Préstamos Bibliotecarios Modelo conceptual de la Clase Material Bibliográfico, definida por mecanismos de herencia Diagrama del modelo de clases conceptuales incorporando los métodos u operaciones por cada clase Representaciones de la clase Préstamo y Copia en el modelo conceptual y en el modelo de diseño Representación de la clase Préstamo en JAVA Diagrama modificado al incorporar la clase Detalla Préstamo Diagrama que muestra la clase Préstamo desde el punto de vista de diseño La clase de diseño Préstamo, vista en código JAVA Diagrama de clases de diseño involucradas en el proceso del préstamo de libros Vista de una ventana de Power Designer para la clase Préstamo Diagrama de clases de diseño incorporando las asociaciones Diagrama que muestra la modificación de la relación entre la clase Préstamo y Detalle Préstamo Diagrama que muestra la jerarquía de herencia del concepto de Material

Bibliográfico

Diagrama que muestra la clase abstracta Material y las clases derivadas específicas de cada material bibliográfico Representación en JAVA de la clase abstracta Material

6

18 20 21 27 37 44 45 64 66 70 71 74 79 80 89 95 96 98 103 111 112 118 122 123 125 128 129 133 134 136 137

32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58.

Arquitectura en tres capas Arquitectura en n-capas Representación de la interacción entre el actor Bibliotecario y el Sistema de Préstamo Bibliotecario, mediante un diagrama de secuencia. Representación del caso de uso Registrar Préstamo, mediante un diagrama de secuencia Representación, en un diagrama de secuencia, del proceso Registrar Préstamo, usando las operaciones de la clase de diseño de la capa de interfaz Diagrama de la interacción entre la capa de interfaz y de la capa de gestión Representación de la composición entre las clases de diseño de la capa de interfaz y de la capa de gestión Representación de la creación de objetos, a partir de la interacción entre capas Representación completa del proceso de Registrar Préstamo, en múltiples capas Visión parcial de la Figura 40, enfocada en la validación del Usuario Representación de la clase de diseño Detalle Préstamo, a partir de los descubrimientos derivados del diagrama de secuencia de la Figura 40 Símbolos usados en un diagrama de actividad Diagrama de actividad para un algoritmo, para calcular una suma de números naturales Primera elaboración del diagrama de actividad para el caso de uso de

Registrar Préstamo

139 140 149 151 153 155 157 160 162 163 164 167 168 171

Continuación de la elaboración del diagrama de actividad para el caso de uso de Registrar Préstamo Continuación de la elaboración del diagrama de actividad para el caso de uso de Registrar Préstamo Diagrama de actividad completo para el caso de uso de Registrar

Préstamo

Diagrama de secuencia de las clases de interfaz y gestión, para el caso de uso de Registrar Préstamo Diagrama de actividad para especificar la operación TieneCopiaPrestada Símbolos utilizados en los diagramas de estados Diagrama parcial de la transición de estados de la copia de un material bibliográfico Diagrama de estado completo para la copia de un material bibliográfico Las pruebas están en todas las fases del Préstamo Unificado, pero aumentan en la fase de Transición Operaciones involucradas en el caso de uso de Registrar Préstamo Especificación de la operación TieneCopiaPrestada Interfaz para Registrar Préstamo Código en JAVA para interfaz IRegistrarPréstamo

7

172 174 176 177 178 180 183 185 190 193 196 198 198

59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72.

Código en JAVA de clase RegistrarPréstamoInterfaz que implementa la

interfaz IRegistrarPréstamo. Componente AdministrarPréstamo en el Sistema Préstamo Bibliotecario Asociación de interfaces para un componente en Power Designer Asociación de interfaces para un componente en Power Designer Clases resultantes del componente de Administrar Préstamo El componente Administrar Préstamo se acopla con el componente usuarios Diagrama de componentes que implementan el Sistema de Préstamo

Bibliotecario

Ambiente para creación automática de la documentación técnica del sistema en Power Designer Elementos de un diagrama de despliegue Equipo cliente del Sistema de Préstamo Bibliotecario Conexión hacia el servidor Web de la Biblioteca, desde Internet o Intranet Diagrama de despliegue del Sistema de Préstamo Bibliotecario Diagrama de despliegue del Sistema de Préstamo Bibliotecario integrando el Sistema Financiero Diagrama de despliegue del Sistema de Préstamo Bibliotecario completo

199 200 200 201 203 203 205 207 208 209 210 211 212 213

ÍNDICE DE TABLAS 1. Posible marco de trabajo del sistema de cajero automático en el marco del proceso unificado 2. Lista de categorías de clases conceptuales. Adaptado de Larman (2003) 3. Representación de clases de la Figura 11 usando la “regla de oro” sugerida por Larman 4. Atributos potenciales de las clases conceptuales del Sistema de Préstamo

Bibliotecario

5. Actualización de los atributos de las clases conceptuales del Sistema de Préstamo Bibliotecario

6. Análisis de atributos por cada uno de los tipos de materiales bibliográficos 7. Métodos identificados en cada una de las clases involucradas en el caso de uso de Registrar Préstamo 8. Actualización de los métodos por cada clase en el Sistema de Préstamo

Bibliotecario

9. Clasificación general de los tipos de pruebas en la Ingeniería de Software 10. Ejemplos de cómo aporta el UP usando el UML en la Ingeniería de Sistemas 11. Relación entre los distintos tipos de pruebas y los módulos creados en el desarrollo del sistema

8

38 67 72 91 93 97 100 102 191 206 214

INTRODUCCIÓN Existen varias formas de acercarse a cualquiera de las temáticas que se abordan en la Ingeniería de Software para tratar de motivarlo a usted hacia ello. Podría escribir sobre la consistencia, las ventajas que se encuentran en el desarrollo de software usando UML apoyado por una herramienta… pero creo que ello no sería suficiente para lograr entusiasmarlo por este tema. Sin embargo, usted me permitirá que le cuente mi experiencia personal, o parte de esta, en el campo de la Ingeniería de Software, la cual me motiva grandemente a escribir este libro, esperando que encuentre en él, las bondades que yo he hallado para mi vida profesional, en el análisis y diseño orientado a objetos, usando UML. Precisamente, puedo empezar mi historia a partir del momento en que comencé a llevar mis cursos orientados a la Ingeniería de Software. Por aquel entonces, iniciando los años 90, hablar de la programación orientada a objetos era una extravagancia digna de los cursos electivos de final de carrera. Mucho menos probable era poder intuir o encontrar algo consolidado en el campo del análisis y diseño orientado a objetos. Por ese entonces, estudiábamos el análisis estructurado. Sin detallar de qué se trata este tipo de análisis, para poder expresarlo gráficamente había que crear los diagramas de flujos de datos, o DFD. Este tipo de diagramas requería, en mucho, especificar procesos y flujos de datos, los cuales consistían, coloquialmente hablando, en hacer bolitas y flechas, respectivamente. Un primer problema al que nos enfrentábamos era que, al carecer de herramientas de software que pudieran, por ese entonces, apoyar las labores de modelado. Los estudiantes nos encontrábamos creando diagramas mediante la ayuda de monedas y reglas. La especificación del llamado diccionario de datos, requerido por esa metodología, era también complejo de realizar, puesto que tenía que sistematizarse sin ningún apoyo automatizado. El cuidado de mantener los diagramas consistentes recaía, exclusivamente, en el cuidado que debíamos tener en su elaboración. Otro problema que encontrábamos era el hecho de tener que plasmar el conocimiento que adquiríamos mediante el análisis de requerimientos, a través de la descomposición en procesos. Esto significaba ver el problema de un sistema solo a través de un comportamiento del flujo de datos a través de dichos procesos. Por ejemplo, si topábamos con un problema referido a la administración de préstamos de una biblioteca, su resolución tenía que irse

9

modelando con procesos que expresaban acciones como: “verificar existencia”, “comprobar atraso”, “registrar préstamo”, “registrar devolución”, “registrar multa”, entre otros. No obstante, en el plano del modelo de la solución, no podían visualizarse los conceptos “puros” del sistema: libro, revista, préstamo, entre otros, ni tampoco la posible relación entre éstos, sus datos y acciones características. Esto tenía que hacerse en otro momento, por ejemplo, cuando se plasmara el modelo de la base de datos. Así, el análisis separaba completamente los momentos de resolución de un problema, es decir, las funcionalidades por un lado, y los datos por otro. Por lo tanto, al entrar a realizar un análisis de requerimientos para definir el componente de software de un sistema, rápidamente tenían que dejarse de lado los conceptos más naturales involucrados en la solución. Todo ello aumentaba el riesgo de no llegar a una solución concordada, usando el análisis estructurado, máxime porque era necesario que en grandes proyectos existieran equipos especializados de análisis, de bases de datos, de diseño de módulos, etc., lo cual implicaba esfuerzos de coordinación muy precisos. Si bien hoy en día dicha coordinación también se requiere, en aquel entonces la dificultad para lograrlo era mayor. Por otra parte, luego de un gran esfuerzo, nos encontrábamos con el resultado de tener muchos diagramas, quizás con gran nivel de detalle, que debían pasar a la fase de diseño. ¿Cómo hacer tal paso? Tal transición no era evidente ni simple. Debían buscarse los procesos de mayor nivel de refinamiento en los DFD, además de tener que identificar “el punto más abstracto de entrada” y el “punto más abstracto de salida”, para luego formar una jerarquía de procedimientos de software. ¿Les parece complejo? Sí, sí lo era, pero no voy a detallar el proceso que seguí para lograrlo. Quiero estar en paz con usted. Pero, en algunos cursos conocí las características del paradigma de orientación a objetos y, una vez graduado, la vida me llevó a enfrentar varios proyectos, varias herramientas de software, varios cambios en la historia de la tecnología, en muy pocos años. Pude comenzar a experimentar la utilización de protocolos de TCP/IP para ejecutar aplicaciones hechas en el sistema operativo DOS, de forma desconcentrada. Al poco tiempo comencé a trabajar en la transformación de aplicaciones de software de un ambiente de “main frame” hacia “cliente / servidor”, bajo el ambiente de “Windows”. Posteriormente sobrevino el advenimiento de las tecnologías de Web y su expansión en Internet, la

10

consolidación de las arquitecturas n-capas y la construcción de componentes. Todo ello en menos de 10 años. Paralelo a todos esos cambios, el mundo de la Ingeniería de Software requería encontrar metodologías que facilitaran la especificación y el desarrollo de aplicaciones, porque cada día aumenta la demanda de software por parte de las organizaciones, a la vez que crece su complejidad e importancia. Al toparme de nuevo con el paradigma de orientación a objetos, mediante el análisis y diseño (usando la notación del Unified Model Lenguaje, UML dentro de una propuesta metodológica, llamada el proceso unificado), me fue posible palpar muchas ventajas en cuanto a la utilización de esta herramienta. He de confesar que, conforme iba capacitándome en su utilización, me sentía cada vez más tentado a rehacer todo el software de un proyecto que coordinaba. Sin embargo, esto no era viable en ese momento, pero a todas luces podía palpar, casi ver, las posibilidades brindadas de obtener, de forma muy natural, los requerimientos de software. Esa forma de desarrollo me posibilitaba especificar tales requerimientos de forma que fuera fácil de comprobar su validez con los clientes, para luego trasladarlos de forma relativamente sencilla, a especificaciones técnicas para desarrolladores. Una vez que profundicé sobre el UML, me fue muy fácil llevar a cabo un nuevo proyecto, usando las posibilidades y ventajas dadas por esa metodología. Con ella, usted se enfrentará a un panorama distinto, con una ingeniería mucho más madura, donde todas las fases se entrelazan de forma “suave” y, gracias a la consolidación del paradigma y los lenguajes de programación orientados a objetos, a un entorno consistente en todas sus fases: desde el tratamiento del problema con los clientes, hasta la programación e implantación del sistema. Ahora bien, para aprender Análisis y Diseño Orientado a Objetos, nos valdremos de algunos apoyos. Uno de ellos es una herramienta existente en el mercado llamada Power Designer, de la compañía Sybase, que nos va a ser útil para ilustrar el desarrollo de los ejemplos. Además, echaremos mano de uno de los lenguajes más difundidos y consolidados en el entorno de los lenguajes de programación orientados a objetos: JAVA de Sun Microsystems. En este momento es posible que usted tenga curiosidad por saber de qué va a tratar este texto. Seguidamente se lo contaremos. Si bien creemos que usted conoce algo sobre el paradigma de Orientación a Objetos, comenzaremos con un breve repaso de éste paradigma que, incluso, nos ayudará a dar un primer encuentro con la notación de UML.

11

Posteriormente, haremos una presentación del Proceso Unificado y el UML. Para ello nos ayudaremos de un ejemplo que introducirá muchos conceptos que, luego, se seguirán reforzando en los siguientes capítulos. A continuación, se abordará el tema de los casos de uso, como una forma de establecer los requerimientos fundamentales del software por construir, así como la forma de especificar dichos fundamentos. Seguidamente entraremos a estudiar el modelo de clases, considerando dos aspectos: en primer lugar, visualizando dicho modelo como la expresión de la arquitectura estática de los casos de uso identificados. Para ello, se abordará un caso de uso particular. En segundo lugar, también analizaremos cómo impacta el modelo de clases, la incorporación de otro caso de uso. Este punto es importante de considerar al tratarse el proceso unificado, como ya se verá en su momento, de un proceso iterativo de construcción de software. En este punto también abordaremos las principales relaciones que se dan entre las clases: asociación, composición y herencia. Definida la arquitectura estática a través de un modelo de clases, estudiaremos la arquitectura dinámica del software mediante diagramas de secuencia, de actividad y de estado. Este modelo permitirá visualizar cómo interactúan entre sí, objetos provenientes del modelo de clases para implementar un caso de uso particular. Los apartados anteriores podrían definir, en general, la fase de análisis: encontrar los casos de uso del software por construir y expresarlos a través de una arquitectura de elementos de software, visualizados mediante clases y objetos interactuando. Sin embargo, la resolución del software por construir, como en toda metodología, debe seguir una estrategia, de acuerdo al contexto técnico donde se encuentre. Además, deberán seguirse criterios de diseño, los cuales no tienen que ver con requerimientos funcionales definidos por el cliente, sino con aspectos como: modularidad, rendimiento, reutilización y muchos otros aspectos en los cuales, los modelos definidos en el análisis, se verán enriquecidos y modificados para cumplir con requerimientos de la fase de diseño. Mediante el conocimiento de estos aspectos, estaremos profundizando en el software que se usará para ilustrar los conceptos. Veremos cómo se modifican los diagramas del análisis, en la medida que se especifican más detalladamente, los modelos que se presentan a lo largo del libro.

12

Se agregarán algunos gestores, que son clases de diseño, que ayudan a proveer acciones que favorecen la creación de objetos, y a coordinar acciones entre estos, así como a asumir algunas funciones de control, que no son propias de las clases identificadas en el análisis. También, dichos gestores son fundamentales en algunas propuestas, como la arquitectura de n-capas. Por último, veremos cómo el proceso de análisis y diseño puede culminar en la generación del código básico de programación, lo cual podrá ilustrar la consistencia que puede encontrarse entre las fases. Sin embargo, para lograr con éxito el estudio de este curso, usted debe dominar, como requisito previo, siguientes conocimientos: ƒ ƒ ƒ ƒ ƒ

Principios de ingeniería de software. Conocimiento del proceso de análisis de requisitos de software. Conocimientos de los principios teóricos del diseño de software. Conocimiento en el paradigma de orientación a objetos. Conocimiento en lenguajes de programación, siendo deseable Java.

13

14

CAPÍTULO

1

GENERALIDADES SOBRE EL PARADIGMA DE ORIENTACIÓN A OBJETOS, EL PROCESO UNIFICADO Y CASOS DE USO

SUMARIO PARADIGMA DE ORIENTACIÓN A OBJETOS Pensar en “objetos”: la abstracción del paradigma La clasificación: una descripción general de los objetos La Herencia: generalizar y especificar soluciones Distintas formas de hacer cosas parecidas: el polimorfismo EL PROCESO UNIFICADO ¿Qué es el Proceso Unificado (UP)? El UP es orientado a casos de uso: historias del sistema El UP se centra en la arquitectura: dar sustento a los casos de uso El UP es iterativo e incremental: la convergencia a una solución UML y el UP CASOS DE USO: LA GUÍA DEL PROCESO Cómo identificar los casos de uso de un sistema Los actores del sistema Casos de uso: cómo se visualizan Relaciones entre casos de uso Especificación básica de casos de uso Especificación detallada de casos de uso

15

OBJETIVOS Una vez que usted estudie este capítulo, podrá llevar a cabo cada una de las siguientes actividades de aprendizaje, que le servirán para comprobar cuánto ha aprendido de este tema. -

Enunciar el significado de abstracción dentro del paradigma de orientación a objetos e identificar atributos y comportamiento de los objetos, dando ejemplos que los ilustren y describiendo el significado de clase dentro del paradigma de orientación a objetos.

-

Dar ejemplos de clases haciendo evidentes el nombre, los atributos y las operaciones o métodos, representándolos esquemáticamente y explicar lo que se entiende por encapsulamiento.

-

Dar ejemplos en donde se haga evidente el significado de polimorfismo en el paradigma de orientación a objetos y explicar en qué consiste la herencia dentro del paradigma y cuáles son sus implicaciones, mediante un ejemplo concreto.

-

Mediante un diagrama ilustrar qué se entiende por casos de uso dentro del Proceso Unificado, ayudándose de un ejemplo concreto.

-

Explicar el significado e importancia de arquitectura dentro del contexto del Proceso Unificado.

-

Enunciar qué se entiende por iteración dentro del Proceso Unificado, justificando su importancia y describir las fases en las que suele dividirse.

-

A partir de un ejemplo que se le suministra, elaborar un esquema en el que se observen claramente las diferentes fases, las actividades y los objetivos que persiguen en cada caso.

-

Partiendo de un ejemplo cualquiera, definir los casos de uso, especificando lo que lleva a cabo cada uno dentro del sistema.

-

A partir de un ejemplo, y utilizando la plantilla definida en el libro, elaborar el llamado curso normal de eventos o escenario del sistema.

16

PARADIGMA DE ORIENTACIÓN A OBJETOS Antes de entrar “de lleno” en el desarrollo de los temas del Análisis y Diseño Orientado a Objetos (que en adelante denominaremos ADOO), es conveniente hacer un breve repaso del paradigma de orientación a objetos. Este repaso no se hará desde un punto de vista histórico, es decir, no nos detendremos en conocer cómo surge este paradigma, cómo se desarrolla o cómo se consolida. Más bien se hará desde el punto de vista de la utilidad que tendrá para este texto, en la medida que es uno de los fundamentos de la metodología y técnicas que vamos a estudiar. De esta forma se revisarán las principales características que definen éste paradigma: la abstracción que lo fundamentan, la clasificación y el encapsulamiento de objetos, el polimorfismo y la herencia.

Pensar en “objetos”: la abstracción del paradigma El paradigma de orientación a objetos es una abstracción que busca representar, en el software, los conceptos del mundo real. De hecho, la palabra “objeto” refiere a algo que es palpable. Tales conceptos pueden ser algo muy concreto, como por ejemplo, “estudiante”, o algo abstracto, como decir “matrícula”. Los objetos contienen dos aspectos fundamentales: sus atributos y su comportamiento. Por ejemplo, si pensamos en un objeto simple, como una pelota, podríamos definirla por algunos atributos, entre ellos: color, volumen, peso. De igual forma, las pelotas tienen algunos comportamientos, muy relacionados con sus atributos, como: “hacerla_rodar”, “pintarla”, “pesarla”, “medirla”. No todas, pero quizás algunas pudieran permitirse “hacerla_rebotar”. Los objetos tienen identidad, es decir, todo objeto es único. Además, presentan un estado, el cual se define por los valores que tienen sus atributos en un momento determinado. Es por ello que una pelota roja es distinta de otra pelota roja, aunque tengan el mismo color, peso y volumen, esto es, que aunque el estado de un objeto sea igual que el de otro objeto, nunca se tratará del mismo objeto. Piense usted en dos personas que sean mellizas. Reflexione en ello y verá con más claridad el significado de lo anterior.

17

La clasificación: una descripción general de los objetos A pesar que los objetos son independientes, pueden clasificarse de una forma general. Podemos decir que todas las facturas, o todas las pelotas pueden describirse de una forma general. Ya sabemos que los objetos tienen atributos y comportamiento. A partir de ello siempre trataremos de identificar, de forma general, cuáles atributos y qué comportamiento pueden tener todos los objetos de una clase particular. En este punto nos topamos con una palabra importante: la clase. La clase vendrá a ser un concepto muy importante del paradigma de orientación a objetos, pues a través de éstas clases lograremos describir todos los objetos pertenecientes a una misma clase. Gráficamente, una clase consta de tres secciones: el nombre, los atributos y las operaciones o métodos. Estos últimos son los que tienen que ver con el comportamiento de los objetos. En la figura 1, podremos ver la clase Pelota, representando los objetos de este tipo. Nombre Atributos

Operaciones

Pelota - color : - peso : - volumen : + + + +

Hacerla_rodar () Pintarla () Medirla () Pesarla ()

Figura 1. La clase Pelota.

En ella pueden notarse las tres secciones que mencionamos. Todas las pelotas que vayan a crearse a partir de esta clase, tendrán esos atributos y esas operaciones. Acá surge algo muy poderoso dentro de esta forma de visualizar nuestras abstracciones. Muchas cosas en el mundo las podemos representar así. Por ejemplo, si pensamos en algo como un libro, de igual forma podemos pensar en sus atributos y las operaciones que podemos hacer con éste.

18

Nombre de la clase Atributos

Libro Autor, Número de páginas, Capítulos, Anexos, ISBN, Resumen

Operaciones

Consultar, Ver resumen, Obtener Autor, Pasar página, Pasar Capítulo

Muchas veces, sin embargo, nos veremos obligados a modelar conceptos más abstractos, como por ejemplo los que podamos hallar en el contexto de una organización. Piense en una orden de trabajo, que es una tarea o actividad que una persona debe hacer y a la cual se le debe dar un seguimiento. Nombre de la clase Atributos

Operaciones

Orden de trabajo Usuario que origina, descripción de trabajo, fecha de solicitud, encargado, estado de la orden (sin asignar, en proceso, cancelada, finalizada), fecha de asignación, fecha de estado final Solicitar trabajo, asignar, cancelar, finalizar

La característica de poder definir clases para los objetos, nos pone ante un panorama particular en el ámbito del paradigma de orientación a objetos: para definir los conceptos relevantes dentro del dominio de un problema por resolver, debe pensarse en sus atributos y comportamiento como un todo. Siendo muy prácticos, debemos pensar que los objetos serán parte de un código de software. Y en ese tanto, tales objetos contendrán los datos que requieren (atributos) y sus procesos (operaciones) residiendo en el mismo espacio. A tal característica la llamaremos encapsulamiento.

La Herencia: generalizar y especializar soluciones Muchas veces en un problema de software podemos encontrar un concepto que tiene, por una parte, atributos o comportamientos comunes, pero de ese mismo problema, se derivan también algunos atributos o comportamientos que son específicos de ese problema en particular. En este caso, para resolver el problema debemos acudir a la capacidad de herencia que tiene este paradigma.

19

La herencia es un mecanismo muy poderoso que permite agrupar en una característica llamada superclase, los atributos y operaciones que son comunes a una o varias clases derivadas, las cuales heredan la definición de dicha superclases. Pongamos el ejemplo de una empresa que maneja clientes. Los clientes pueden ser de dos categorías: clientes físicos (es decir, personas como usted o como yo) y clientes jurídicos (en este caso, organizaciones, empresas, corporaciones, entre otros). Para representar a los clientes de esta compañía, dentro del software, podríamos recurrir a dos estrategias. La primera sería crear una clase para cada una de los tipos que describimos. En la siguiente figura encontramos una ilustración de esta estrategia. ClienteJurídico

ClienteFísico -

Identificación Apellido Nombre DirecciónPostal Teléfono CorreoElectrónico

+ + + + + + +

ClienteFísico () ActualizarDirección () ActualizarTeléfono () ActualizarCorreo () ObtenerDirección () ObtenerTeléfono () ObtenerCorreo ()

: : : : : :

-

Identificación Nombre TipoOrganización DirecciónPostal Teléfono CorreoElectrónico

: : : : : :

+ + + + + + +

ClienteJurídico () ActualizarDirección () ActualizarTeléfono () ActualizarCorreo () ObtenerDirección () ObtenerTeléfono () ObtenerCorreo ()

Figura 2. Clase para cada tipo de cliente.

Tal como se aprecia, cada una de las clases representadas, puede manejar los clientes físicos o jurídicos en un contexto determinado. No obstante, puede notarse también que existen muchos atributos y operaciones comunes en ellos. Esto se debe a que, debido a que el concepto de cliente es un concepto general, por cada uno de los tipos de clientes que encontremos, tales características generales se repiten. Por lo tanto, otra estrategia que podemos realizar es crear una jerarquía donde una superclase llamada Cliente reúna las características comunes a todos los clientes y dos clases derivadas, ClienteFísico y ClienteJurídico, que representen la especialización para cada uno de estos. En la siguiente figura se representa esta jerarquía:

20

Cliente -

Identificación DirecciónPostal Teléfono CorreoElectrónico

: : : :

+ + + + + + +

Cliente () ActualizarDirección () ActualizarTeléfono () ActualizarCorreo () ObtenerDirección () ObtenerTeléfono () ObtenerCorreo ()

ClienteJurídico

ClienteFísico - Apellido : - Nombre :

- Razón Social : - TipoOrganización :

+ ClienteFísico ()

+ ClienteJurídico ()

Figura 3. Superclase de Cliente y clases derivadas por tipo de cliente.

En ella vemos cómo la clase Cliente reúne los atributos y operaciones que son comunes a todos los tipos de cliente que el software vaya a manejar. Para cada una de las clases derivadas, tal como se representan en las clases de ClienteFísico o ClienteJurídico, encontramos solamente los atributos y operaciones que son propios de cada uno de éstos. La jerarquía debe indicarnos que cada una de las clases derivadas de la superclase tiene, también, TODOS los atributos y operaciones de esta superclase. Por ejemplo, todos los tipos de clientes tienen una identificación (sea cédula de identidad o cédula jurídica), una dirección postal, un teléfono o un correo electrónico. No obstante, solamente un cliente físico tendrá un apellido y nombre, contrario a un cliente jurídico que tendrá una razón social y un tipo de organización (pública, privada, entre otras). Además, todas las operaciones que se definan para Cliente serán también operaciones para ClienteFísico o ClienteJurídico. Lo anterior nos da una ventaja de que por cada tipo de cliente que estemos encontrando, nos enfocaremos en identificar las diferencias, sin preocuparnos por detalles que ya la superclase ha resuelto.

21

Distintas formas de hacer cosas parecidas: el polimorfismo Piense por un instante que muchas veces en la vida hacemos cosas que, como acciones expresadas en verbos, las llamamos de forma semejante, pero que pueden resultar con efectos u objetivos distintos. Por ejemplo, cada uno de nosotros tiene un ritmo natural y propio para caminar. Si salimos de nuestra casa para ir a algún lado, iremos caminando con esa forma propia de cada uno (no es extraño que alguien exprese algo como “ese es el caminado de fulano de tal”). Sin embargo, muchas veces tenemos que modificar la forma en que caminamos y, si bien se trata de caminar, ciertamente debemos tener en cuenta otros parámetros a la acción. Por ejemplo, frente a una situación de peligro podríamos caminar de forma precavida o bien acelerada. Dependiendo de algo en especial, como pasar por una vitrina y darnos cuenta que algo nos interesó, podríamos caminar hacia atrás para poder ver el objeto que llamó nuestra atención. Entonces, lograríamos expresar la acción de caminar con distintos parámetros, y siempre nos estaríamos refiriendo a una acción que se llama igual. En la siguiente tabla encontramos algunos ejemplos de ello. Acción

Parámetros

Lo que expresa

Caminar

Ninguno

Nuestro caminar normal

Caminar

Velocidad

Caminar lenta o rápidamente

Caminar

Velocidad, Dirección

Caminar

Velocidad, Dirección, Forma

Caminar con una velocidad determinada, hacia atrás o hacia delante Caminar con una velocidad y dirección determinadas, de forma normal o precavida

En el paradigma de orientación a objetos, la característica de que un objeto pueda realizar una determinada acción, llamada igual, pero que puede diferenciarse por un conjunto de parámetros distintivo, se llama polimorfismo. Por ejemplo, si viéramos el ejemplo anterior en perspectiva de un lenguaje de programación, podríamos escribir un código como el que sigue: persona.Caminar(); // Caminar de forma normal persona.Caminar(velocidad); // Caminar con una velocidad determinada

22

persona.Caminar(velocidad, dirección); // Caminar con una velocidad y dirección determinada persona.Caminar (velocidad,dirección,forma); // Lo anterior con una forma determinada Acá podemos notar cómo la acción se llama igual (caminar). No obstante, las distintas formas de caminar se distinguen por la cantidad de parámetros que acepte y el tipo de cada uno de éstos. Esta forma de polimorfismo se denomina sobrecarga de operaciones. Otra forma de poder visualizar el polimorfismo es a través de la herencia. Veamos el siguiente ejemplo. Suponga, en la Figura 3, que existen dos formas distintas para calcular impuestos para un cliente, según el tipo que se trate: físico o jurídico. La superclase Cliente, podría definir una operación llamada CalcularImpuesto, la cual se dice, es una operación abstracta. Esto último significa que, si bien (por requerimientos de la solución y por diseño de esta), se sabe que para cada tipo de cliente se debe calcular un impuesto (de venta o de valor agregado), tal operación no puede implementarse en la superclase, porque dicha implementación varía, como ya se mencionó, de acuerdo al tipo de cliente. Por lo tanto, cada una de las clases derivadas, ClienteFísico y ClienteJurídico, deberán implementar la operación. Desde el punto de vista conceptual, al tratar con el concepto particular de Cliente, todo cliente jurídico es un cliente y todo cliente físico es un cliente. La forma de “verse” y de hacer las cosas, como calcular impuesto, es distinta. Entonces, el cliente tiene muchas formas de verse en la solución que se trata de realizar. Esto es polimorfismo. Quedan así expuestas las principales características del paradigma Orientado a Objetos. Recordemos que estas características incluyen: La abstracción de que los elementos de software los podemos ver como objetos. La clasificación que permite definir, de forma general, todos los objetos de una clase particular que tienen atributos y comportamiento propios. La encapsulación, que ayuda a reunir, tanto datos, como operaciones, en un solo elemento de software. La herencia, que es un mecanismo que permite racionalizar una solución a través de la creación de una jerarquía que distribuye de la parte superior a la inferior, las

23

características de atributos y operaciones comunes y que se complementa de forma importante con El polimorfismo que favorece que podamos definir para un mismo concepto, distintas formas de comportarse o verse, a través de las operaciones o de la herencia. EL PROCESO UNIFICADO La disciplina de la Ingeniería de Software ha tratado siempre de proveer una serie de metodologías que puedan facilitar el proceso de construcción de una solución. Ese proceso ha buscado adaptarse a la naturaleza cambiante de los proyectos y de las soluciones. Ciertamente nosotros podemos suponer que al inicio de un proyecto se tenga una idea un tanto vaga de lo que se quiere, aunque no se dude de la importancia de lo que desea obtenerse. De igual forma, el cliente podrá saber, de forma muy general, qué solución de software quiere desarrollarse, porque ella es fundamental para los objetivos de su organización. Un proceso de desarrollo que busque identificar los factores críticos, y por ende más riesgosos, que permita ir en un proceso incremental de la solución, es altamente deseable. Precisamente, el llamado Proceso Unificado es una forma de desarrollo de software que permite ir creando una solución de forma robusta, con un adecuado manejo del riesgo y de forma incremental. En las siguientes páginas buscaremos revisar los conceptos fundamentales de esta forma de trabajo: los casos de uso como guía del proceso, la arquitectura como sustento de la solución y el desarrollo iterativo e incremental, como una forma de realizar una solución adecuada a los requerimientos del usuario. Se tomará un ejemplo que, se espera, contribuya a aclarar algunas de las bases importantes que se introducirán en este capítulo. En los capítulos siguientes, cuando se profundicen varios conceptos que seguidamente se introducen, se usará otro ejemplo.

¿Qué es el Proceso Unificado (UP)? Larman (Larman, 2003) señala que, informalmente, un proceso de desarrollo de software es un enfoque para la construcción, desarrollo y mantenimiento de software. En ello, el Proceso Unificado (en adelante UP, por sus siglas en inglés), se presenta como uno de los procesos de desarrollo de software más difundidos

24

hoy en día, que busca aprovechar las ventajas del paradigma de orientación a objetos, en las disciplinas de Análisis y Diseño (el cual llamaremos A/DOO, es decir Análisis/Diseño Orientado a Objetos). Tres aspectos caracterizan al UP: ƒ ƒ ƒ

Se orienta a casos de uso. Se centra en la arquitectura y Es iterativo e incremental.

¿Qué es cada uno de estos conceptos? Procederemos a aclararlos a continuación. El UP es orientado a casos de uso: historias del sistema Vamos a entender, los casos de uso como la interacción que tienen los usuarios del sistema con éste. Para identificar los casos de uso pueden enlistarse las funciones, actividades u objetivos que tiene un usuario particular en el sistema. Podríamos decir, entonces, que los casos de uso pueden interpretarse como las tareas del sistema que se llevan a cabo, originadas por alguien. ¿Quién es ese alguien? Ese alguien son los llamados actores en el sistema. Un actor corresponde a un perfil de usuario, el cual puede ser una persona u otros sistemas. El propósito de identificar actores obedece a que debemos saber quiénes son los usuarios del sistema y cómo vamos a categorizar a dichos usuarios. Un actor es todo aquel (personas) o aquello (sistemas, dispositivos) que usan el sistema, ya sea para alimentarlo o para recibir salidas de éste. Un actor, por lo tanto, lo podemos conceptualizar, ya sea que se trate de una persona, un dispositivo u otro sistema, como algo o alguien que usa o produce datos e información del o para el sistema. Podemos darnos un ejemplo clásico, como los cajeros automáticos. Todo sistema debe poder caracterizarse por los servicios que va a brindar a quienes se sirven de él. En este caso, podemos pensar que un cliente podrá acceder a servicios como “retirar efectivo”, “transferir fondos”, “consultar saldo”, “realizar pagos”, entre otros. Estos servicios pueden verse como los objetivos de un sistema de cajero automático. Cada uno de los servicios que se le ofrecen a un cliente podrán ser vistos como casos de uso: el caso de uso de “Retirar efectivo”, el caso de uso de “Transferir fondos”, el caso de uso de “Consultar saldo”.

25

Con respecto a los actores, inmediatamente podemos pensar en el cliente (muchos de nosotros hoy en día hemos usado un cajero automático), como un actor del sistema de cajeros automáticos. El cliente interactúa con este sistema y, en gran medida, para él es quien se ha creado el sistema. No obstante podemos pensar que existen otros actores importantes del sistema. Usted ha visto que en ciertos momentos llegan funcionarios del banco o entidad financiera dueña de los cajeros automáticos a realizar procesos en ellos, tales como alimentarlos de efectivo, descargar la información almacenada, realizar mantenimiento, entre otras acciones. Vea que, con respecto a un funcionario, al cual podríamos denominar operario, encontramos otras funcionalidades en este sistema y como tal, también estamos identificando otro actor del sistema. Las funcionalidades como “Descargar información almacenada”, “Realizar mantenimiento”, “Alimentar efectivo” se pueden ver como casos de uso. Finalmente, podemos pensar que el cajero automático es un sistema que se relaciona con un sistema bancario central: todas las acciones que se dan en el cajero deben estar apoyadas por el sistema bancario central donde, entre muchas cosas, se encuentra la información de la o las cuentas asociadas con la tarjeta que se emplea para el uso del cajero. El sistema bancario debe, además, apoyar las acciones de registro de transacciones, de actualización de saldos, de comunicar a otras entidades relacionadas con los servicios ofrecidos en el cajero automático entre muchos. Identificar los casos de uso nos da una forma de poder ir listando los objetivos y los requerimientos del sistema por parte de una serie de interesados, en este caso, los actores que podamos encontrar en el sistema. Un caso de uso es una forma relativamente sencilla de especificar los objetivos de un sistema. Por eso constituye una de las bases principales del UP. Describir lo que hace un caso de uso es básicamente describir una historia, como lo afirma Larman (Larman, 2003). Las historias, esencialmente nos refieren a pensar en narraciones, es decir, que la descripción de los casos de uso pasa por escribirlo en alguna lengua natural, no en términos de lenguajes informáticos. Más adelante veremos un ejemplo de ello. Para visualizar gráficamente un caso de uso, se recurre a un diagrama de casos de uso, donde se ven las interacciones de los actores con los casos de uso identificados. Para el caso del cajero automático, puede hacerse un diagrama de casos de uso como el que sigue.

26

Alimentar efectivo

Validar cliente

Operario Cliente Descargar información Consultar saldo

Actualizar saldo Retirar efectivo



Sistema Bancario Transferir fondos

Figura 4. Diagrama de casos de uso parcial del sistema de cajero automático.

Note que en el diagrama están varios de los casos de uso que anteriormente se identificaron para cada uno de los actores (o sea, los usuarios del sistema). No obstante, el diagrama puede ayudarnos a comprender y visualizar cómo interactúan los actores del sistema. Debemos siempre hacernos a la idea de que los casos de uso también representan los objetivos del sistema expresados como las funcionalidades que esperamos obtener. Por lo tanto, en los diagramas de casos de uso podemos ubicar tales objetivos del sistema de una forma relativamente sencilla. Por otra parte, describir un caso de uso es, como se mencionó anteriormente, describir una historia. Y para describir una historia, podría recurrirse a muchas formas de hacerlo. Por ejemplo, podría ser un texto simple y llano. Entonces la descripción de un caso, pongamos el de “Retirar efectivo”, podría describirse como:

27

Caso de uso

Retirar efectivo

Descripción El cliente, plenamente identificado ante el sistema, procede a digitar un monto múltiplo de 1000, el cual representa el monto que desea retirar. El sistema comprueba que el cliente tenga el saldo suficiente para retirar dicho monto. Si es así, el sistema comprueba que el cajero tenga la cantidad suficiente de fondos, o bien la combinación de billetes para dispensar esa cantidad. Si es así, el efectivo se dispensa, se actualiza el saldo de la cuenta del cliente, se actualiza la información del efectivo disponible y las denominaciones disponibles dentro del cajero y el caso de uso termina. Observando de nuevo la Figura 4, vemos cómo se agrega un caso de uso llamado “Escoger servicio”. Este está relacionado con todos los casos de uso con los cuales interactúa el cliente. La relación se describe a través de un estereotipo llamado “uses” (usa), el cual establece que un caso de uso usa a otro. En el siguiente capítulo se profundizará más con el tema de los casos de uso. Un caso de uso descrito en la forma que se hizo anteriormente se llama descripción breve de casos de uso, la cual consiste en expresar en un párrafo, el escenario que se da en éste. La otra forma de descripción que se tratará en esta unidad didáctica es la llamada descripción detallada, donde se describe un escenario en el cual, mediante una serie de pasos numerados, se especifica lo que debe cumplir el caso de uso para lograr su objetivo. Además, se definen las condiciones previas que deben cumplirse para que el caso de uso pueda darse, los actores involucrados en éste, las posibles fallas o excepciones dentro del escenario y los cursos alternativos que podría tener el caso de uso al considerar tales fallas. Una descripción cercanamente a una descripción detallada, podría ser la siguiente.

28

Nombre

Retirar efectivo

Actor principal

Cliente

Meta en el contexto

Un cliente con una cuenta bancaria y tarjeta de débito o crédito podrá retirar efectivo de un cajero automático, con lo cual se actualiza el saldo de su cuenta.

Condiciones previas

El cajero automático deberá estar habilitado. El cliente previamente se ha identificado en el sistema.

Escenario

El caso de uso inicia cuando el cliente ha escogido la opción de “Retirar efectivo” en la opción del sistema. 1. El cliente digita el monto por retirar. 2. El sistema comprueba que el monto por retirar es menor al límite del cliente. 3. El sistema actualiza el saldo del cliente 4. El sistema dispensa el efectivo 5. El cliente retira el efectivo de la ranura. 6. El sistema completa la operación.

Excepciones

En el paso 1, si el monto del retiro no es múltiplo de un número n, entonces el sistema indica “Por favor digite un número múltiplo de n”. (considerar n = 1000) En el paso 2, si el sistema comprueba que el monto por retirar es superior al límite del cliente, entonces el sistema indica “Por favor indique un monto menor”. En el paso 2, si el monto supera el saldo del disponible en el cajero, entonces el sistema indica “Por favor indique un monto menor”. En el paso 3, si no puede actualizarse el saldo, entonces el sistema indica “No puede realizarse la operación en este momento” y el caso de uso termina. En el paso, si el cliente no retira el efectivo después de 10 segundos, el dinero es devuelto al cajero, la tarjeta retenida y el caso de uso termina.

29

Observe que la descripción anterior es más formal del caso de uso, que la que se denominó como “breve”. Los casos de uso descritos de esa forma pueden especificar condiciones que deben darse en el sistema, los cuales deben ser considerados por los ingenieros de sistemas y de software. Note, por su parte, en las excepciones; estas se refieren a un paso particular en el escenario del caso de uso. Por ejemplo, la primera excepción que se identifica indica “en el paso 2”, refiriéndose que se trata del paso del escenario número 2. Ahí se está describiendo un curso alternativo que debe tomar el caso de uso a la secuencia normal de pasos que se describen en el escenario (en este caso, el sistema indica el mensaje “Ingrese un monto menor” y queda a la espera). En algunos casos ese curso alternativo puede significar la finalización de ejecutar el caso de uso. Como ejercicio, trate de desarrollar la descripción de alguno de los otros casos de uso identificados. Para ello note que las acciones descritas en el escenario son siempre las que tienen relación con alguna acción en el software o en el sistema. Por ejemplo, acciones que haga la persona, como por decir, “el cliente abre la puerta y camina hacia el cajero”, no vienen al caso. En resumen, el hecho de que el UP se base en casos de uso, da la ventaja que esta forma de trabajo ayuda a identificar todas las funcionalidades de un software en perspectiva de los objetivos de los usuarios. E igualmente, tal como se verá, constituirá la base para validar el trabajo técnico que se realizará posteriormente por los ingenieros de software, en las fases de análisis y diseño.

El UP se centra en la arquitectura: dar sustento a los casos de uso Cuando se piensa en el término “arquitectura”, nos puede referir a un concepto de solidez, de que existe un esfuerzo de ordenar y dar una solución de espacio, de funcionalidad a un problema o requerimiento de un cliente. En la arquitectura clásica, para resolver aspectos de una casa o de un edificio, eso es válido. Para el caso de la arquitectura en la ingeniería de software, tenemos que acercarnos a pensar de una forma semejante. Quizás nos pueda ayudar a pensar que la arquitectura podría ser, además de una disposición de elementos, también un sistema. En una casa, los recintos como dormitorios, comedor, cochera, servicios sanitarios, entre otros, tienen una función y objetivos específicos por sí mismos. Pero, además, deben acomodarse, interactuar y relacionarse de la mejor forma, para que la casa funcione bien (para

30

evitar, por ejemplo, que por problemas de espacio u otros motivos, la alacena se coloque en la ducha). Con esta misma lógica, debemos comenzar a pensar en los elementos y las relaciones que deben darse en el software, para cumplir con los objetivos del sistema. ¿Quién nos indican tales objetivos? Eso logra averiguarse a través del trabajo que hayamos realizado, identificando casos de uso. De acuerdo con Booch, Jacobson y Rumbaugh (1999), una arquitectura se necesita para comprender el sistema, organizar el desarrollo, fomentar la reutilización y hacer evolucionar el sistema. Para comprender un sistema se requiere “entrenar” a las personas involucradas en él, desde los clientes, pasando por los ingenieros, los programadores, hasta los técnicos en soporte, etc., de tal forma que puedan comunicarse por medio de modelos donde se expresa la solución que va logrando obtenerse. El UML, a través de sus diagramas, ayuda a que esta comprensión se dé. Piense que en un proyecto grande pueden intervenir muchas personas las cuales, incluso, pueden estar dispersas geográficamente. Por lo tanto, tal comunicación estandarizada, que provoque una mayor comprensión del trabajo que se está llevando a cabo, es sumamente importante. Cuando se habla de organizar el desarrollo, puede decirse que se busca partir el problema en un conjunto de elementos previendo, eso sí, que tales elementos puedan luego “empalmarse”. Tal división puede hacerse, en grandes proyectos, a través de subsistemas. En una organización puede hablarse de un subsistema financiero, un subsistema de relaciones con el cliente, un subsistema de aprovisionamiento, entre muchos otros. Claro está que si bien cada uno de estos subsistemas tiene funciones y objetivos específicos, deben comunicarse y, de hecho, están íntimamente relacionados. Es así como, por ejemplo, en una empresa fabricante, los insumos, el proceso de fabricación de sus productos, los gastos de publicidad y mercadeo, las ventas, etc., afectan el subsistema financiero y debe preverse que estos se comunican para garantizar el buen funcionamiento de la empresa. En el caso de nuestro sistema del cajero automático, ¿qué subsistemas podemos encontrar? Si bien podría aparentar ser un sistema pequeño, hay elementos muy especializados los cuales, por esa naturaleza, podrían separarse para su desarrollo: el manejo de los dispositivos como el lector de tarjetas, el contador de efectivo, la comunicación con el servidor del banco, entre otros. De todas formas, al igual que se separan tareas, deberán preverse las uniones o interfaces, mediante las cuales el producto requerido será armado.

31

A lo interno de los subsistemas, igualmente, encontraremos elementos que usaremos o desarrollaremos para conseguir lo que requerimos para el producto que necesitamos crear. Hay algunos elementos esenciales que se combinan en su diseño y funcionamiento: los objetos agrupados en clases. Por fomentar la reutilización, debemos entender que un objetivo que se persigue en la ingeniería de software, es que las soluciones (o parte de ellas) que se han generado para un problema particular, puedan ser reutilizadas en la solución de otro problema. Precisamente, una arquitectura busca crear componentes de software que bien pueden acomodarse en soluciones pertenecientes a otros dominios del problema. No es de esperar que una organización tenga que hacer un subsistema financiero, cada vez que inicia el desarrollo de un sistema nuevo. Ya sea para un sistema de ventas, de aprovisionamiento, de matrícula, o lo que fuere que emprenda la organización, esta sabrá que existe un software orientado a las operaciones financieras que podrá darles servicio en cada problema de software que tengan que resolver. Por último, todo sistema está sujeto a cambios. La utilización misma del sistema, la formulación de nuevos objetivos, la experiencia de la organización, la respuesta a nuevos retos, harán que exista la necesidad de que éste evolucione. Por lo tanto, es crucial tener una arquitectura bien planteada, fuerte, flexible, donde el impacto del cambio pueda manejarse convenientemente, y donde la ampliación de las funciones pueda darse minimizando los efectos sobre lo que ya está hecho. Sabemos que los retos a los que se somete una arquitectura son muy altos. Es necesario, por lo tanto, que aprendamos a visualizar que todos los elementos que vayamos construyendo, tengan un proceso de construcción que permita obtener una arquitectura con características como la que hemos señalado. Los casos de uso son importantes en ese objetivo, porque nos permitirán identificar aspectos claves de la arquitectura. Algunos de éstos casos de uso son esenciales en ésta arquitectura, porque constituyen elementos clave en la funcionalidad esperada del sistema y, por lo tanto, harán que podamos visualizar qué aspectos en cuanto a subsistemas, componentes, clases, entre muchos otros, son vitales. En este libro nos enfocaremos principalmente en el desarrollo de modelos de clase, como parte de la formación fundamental que debemos aprender para diseñar una arquitectura fuerte en el ámbito del problema que tratamos. Más adelante estudiaremos con detalle cómo hacer tales modelos.

32

No obstante cabe señalar, que es fundamental comenzar siempre por identificar los conceptos que vayamos reconociendo dentro de los requerimientos que se especifican en el problema que necesitamos resolver. Al tener identificado un concepto, debemos preguntarnos cómo se relaciona con otros conceptos y, de alguna forma, qué características de atributos y comportamiento podría tener el concepto identificado. Esto quizás llevará algún tiempo, pero en un proceso de muchas iteraciones, podríamos tener un panorama completo del o de los conceptos involucrados, los cuales se expresarían mediante modelos de componentes, de clases y de interacción. Tales modelos se explicarán a lo largo del libro y, veremos, como en ellos son fundamentales los casos de uso. Con estos modelos tendremos dos visiones de la arquitectura. Por una parte una arquitectura estática, la cual muestra la disposición y organización de los elementos del sistema y, por otra parte, la arquitectura dinámica la cual permite ver cómo interactúan esos elementos para poder resolver un objetivo particular del sistema. Ese objetivo particular ha sido definido previamente… ¡como un caso de uso!

El UP es iterativo e incremental: la convergencia a una solución Abordar una solución de software implica muchos riesgos. Uno de los más importantes es, sin duda, no comprender bien los requerimientos del usuario y, por ende, desarrollar una aplicación errónea. Al afirmar que es “errónea”, se asume que esta puede estar diseñada, codificada y probada de la forma más depurada técnicamente hablando… pero que lastimosamente no responde a las necesidades del cliente. Para minimizar este riesgo, el UP plantea que el desarrollo del software sea iterativo, es decir, que los proyectos de software se dividan en ciclos. Estos deben ser de una duración relativamente corta, en general de 4 a 6 semanas. De acuerdo con Larman (2003), algunas de las ventajas de adoptar este enfoque son: ƒ

Involucra continuamente a los usuarios para evaluación, retroalimentación y requisitos.

ƒ

Aborda aspectos de alto riesgo en las primeras iteraciones.

ƒ

Construye, en las primeras iteraciones, una arquitectura que constituye un núcleo primario consistente.

33

ƒ

Verifica la calidad continuamente, ya que se desarrollan pruebas, oportuna y frecuentemente.

El riesgo de hacer un mal trabajo se reduce, pues este se circunscribe a una sola iteración, en vez de arrastrar mucho tiempo un error, evitando así, que se descubra únicamente al final de todo el proceso. Esas características son muy valiosas para desarrollar un software que responda a las necesidades planteadas. Veamos. Involucrar continuamente al usuario en el proceso, busca tener garantía de que el trabajo que se desarrolla estará de acuerdo con las expectativas de éste último. Trabajar en iteraciones o ciclos cortos implica ir generando avances de forma continua. Así, el usuario logra darse cuenta de lo que va resultando del proceso conjunto de elaboración del producto. De esa forma, tiene la posibilidad hacer sus observaciones, de manera que se enriquezca el proceso, a la vez que los ingenieros propician la forma en que los requerimientos pueden ir refinándose, o bien, mejorándose durante el proceso. Lo anterior trata de manejar una realidad ineludible: los clientes no pueden expresar todas sus necesidades al inicio. Durante el inicio del proyecto, al elaborar los casos de uso, pueden determinarse aquellos ciclos que implican mayor riesgo. Por ejemplo, dentro de la visión del negocio, un caso de uso que contenga un manejo estratégico de la relación con los clientes, o bien, que sea fundamental en el proceso productivo de la organización, se identificarían como casos de uso claves dentro de las expectativas del sistema por construir. Tanto el equipo de ingeniería, como el de usuarios, pondrán especial cuidado en su construcción. El tratar estos casos de uso pueden tomarse en cuenta aspectos como:

Facilidad de uso. ¿Quién debe usar esas funcionalidades? ¿Qué habilidades se espera que tenga el usuario? ¿Deben realizarse versiones en otros idiomas? ¿Cómo hacer fácil el uso del producto hacia el mercado meta, o el recurso humano interno que se espera use este software?

Robustez. ¿Cuánto tienen que protegerse esas funcionalidades ante un uso incorrecto o malintencionado del software?

Disponibilidad.: ¿Qué costo implica no tener disponibles las funcionalidades? ¿Deberá tenerse un servidor espejo en caso de que falle el principal?

Datos clave para la generación de información. ¿Cuánto depende la organización de los datos capturados por estas funcionalidades?

34

Es posible listarse muchas más cosas que puedan identificarse como riesgos y, dentro de éstas, formular las preguntas de cuáles medidas pueden tomarse para minimizarlos. La posibilidad de ir convergiendo, iterativamente a la solución, con la participación del usuario, hace posible disminuir el riesgo de que el producto sea solamente fruto de la imaginación de un ingeniero de software. Gente clave del negocio, como diseñadores gráficos, mercadólogos, personal de venta, de recursos humanos, entre otros, debe participar del proceso. Por su parte, expertos en infraestructura tecnológica deben intervenir para diseñar qué arquitecturas de equipos, de telecomunicaciones y de bases de datos son las adecuadas para manejar los aspectos de mayor riesgo en el proyecto. El hecho de que estas acciones se lleven a cabo al inicio del proyecto, significa una gran ventaja sobre las metodologías tradicionales, que suelen identificarlas al final en la fase de pruebas. El análisis de los casos de uso también puede generar una arquitectura base para el manejo de las aplicaciones de software por desarrollar. A medida que vayan construyéndose más casos de uso, esta podrá irse enriqueciendo. Ahora bien, hemos hablado de iteraciones y de desarrollo del proyecto con esta visión, pero, ¿cómo se visualiza ello? De acuerdo con Jacobson, Booch y Rumbaugh (1999) que son los “padres” del UP, las actividades e iteraciones en un proyecto de este tipo se dividen en cuatro fases, las cuales se describen a continuación: Inicio. En esta etapa se lleva a cabo una descripción inicial del producto final, a partir de las ideas presentadas, y se establece el análisis del negocio para el producto. Los autores indican que en esta fase se responde a preguntas tales como: ¿cuáles son las principales funciones del sistema?, ¿cómo podría ser la arquitectura del sistema?, ¿cuál es el plan de proyectos y cuánto costará desarrollar el producto? Un modelo de casos de uso empleando la descripción breve y visualizando cuáles de estos casos de uso son los más críticos para el proyecto, puede responder a la primera pregunta. En tanto, la segunda pregunta se respondería esbozando cuales serían los principales subsistemas que habría que desarrollar. Piense, por ejemplo, que si se tratara de una universidad, algunos de esos subsistemas serían: de matrícula, de registro, de planificación docente, de administración, entre muchos otros que puedan identificarse. En esta fase también se identifican y priorizan los riesgos más importantes que deban tratarse y se estima el tiempo, los recursos y los costos del proyecto, de forma aproximada.

35

Elaboración: en esta fase se desarrollan, de forma detallada, los casos de uso, en especial los más críticos. Se elabora la arquitectura del sistema y se hacen las estimaciones más precisas, por parte del director de proyecto, en cuanto a tiempo y recursos (materiales y humanos), para terminar éste. En este punto debe preguntarse si, tanto los casos de uso como la arquitectura, están lo suficientemente estables y desarrollados, así como si los riesgos están bien controlados y el plan bien elaborado para comprometerse con el desarrollo total del proyecto. Construcción. En esta fase se crea el producto, sustentado en las especificaciones de los casos de uso y la arquitectura elaboradas. Esta fase, si bien es en la que más recursos se usan y está previamente especificada, no está exenta de que en el transcurso, los ingenieros descubran mejores formas de hacer las cosas, aunque se esperaría que fueran cambios de menor importancia en el diseño de la arquitectura. Al final se obtiene una versión preliminar del sistema, que debe probarse. Transición. Esta fase cubre el periodo en que se libera una versión “beta” del producto para que sea utilizado por un grupo reducido de usuarios. Estos, como parte de la validación que llevan a cabo, hacen observaciones y detectan errores, que luego se corrigen. Se procede, seguidamente, con la producción de la versión final, la cual se acompaña de la capacitación, de los procesos de ayuda para la comunidad de usuarios, así como en la atención de posibles fallos que se encuentren durante su aplicación. Estos mismos usuarios pueden generar una versión incrementada del producto actual (llamada también, versión delta), o bien, de no ser tan urgentes, se pueden guardar para la siguiente versión del producto. Las actividades propias de la ingeniería de software, como la recopilación de requisitos, el análisis de éstos, el diseño, la implementación (entendida como codificación o programación) y las pruebas, pueden verse en qué intensidad se dan en cada una de las fases del UP. La siguiente figura puede darnos idea de ello.

36

Actividades fundamentales Requisitos

Fases Inicio

Elaboración

Construcción

Transición



Iter #n - 1

Análisis

Diseño

Implementación

Pruebas

Iter #1 Iteraciones

Iter #2

...





Iter #n

Figura 5. La conceptualización del UP. Fuente: adaptación de Booch et al. (1999)

Si nos fijamos en la figura anterior, se observa que, en primer lugar, hay que considerar que las actividades fundamentales de la ingeniería de software se encuentran presentes a lo largo de todo el proyecto. No obstante, su intensidad será más alta en ciertas fases. Por ejemplo, la implementación se hace más notoria en la fase de construcción, o bien, el diseño se hace presente en las últimas iteraciones de la fase de elaboración. Sin embargo, la misma naturaleza iterativa del proyecto nos revela que en cada nueva iteración podemos hacer los cuatro tipos de actividades. Sin embargo, de acuerdo con la evolución del proyecto, varios aspectos de la resolución de la formulación de requisitos, de su análisis, o la definición del diseño, van consolidándose y, cada vez menos, van a sufrir modificaciones. Cada iteración debe definir un resultado en lo que al proceso del software se refiere. Un ejemplo, referido a nuestro cajero automático, podría visualizarse de la siguiente forma

37

Fase Inicio

Actividad Requerimientos Requerimientos Requerimientos / Análisis Requerimientos / Análisis Análisis / Prueba Análisis / Diseño

Elaboración

Análisis / Diseño / Prueba Requerimientos / Análisis / Diseño / Prueba Diseño Diseño / Implementación

Construcción

Análisis / Diseño Diseño / Implementación Implementación / Prueba Implementación / Prueba Implementación

Transición

Implementación / Prueba Implementación / Prueba Prueba Implementación / Prueba

Objetivo Redactar un documento de referencia de los objetivos del proyecto. Definir un cronograma base, e identificar las funcionalidades críticas del servicio sanitario. Definir el diagrama de casos de uso, con una descripción básica de estos. Elaborar un documento que resuma: la definición del proyecto, los casos de uso, los casos de uso crítico y la arquitectura básica para el cajero automático. Detallar los casos de uso de Retirar efectivo y Transferir fondos. Definir el modelo de clases para sustentar los casos de uso detallados en la iteración anterior. Definir el detalle de los casos de uso de “Actualizar saldo” y “Validar usuario”. Ajustar el modelo de clases como consecuencia del análisis de los casos de uso. Elaborar un documento con el modelo de clases de negocio y los casos de uso detallados. Diagramas de interacción de análisis. Definir el dispositivo de lectura de la tarjeta y la clase de diseño encargada de hacer interfaz con el sistema. Definir los dispositivos de comunicación con el servidor central y los protocolos de seguridad y cómo definir la interfaz para el sistema de éstos. Definir el detalle del caso de uso de “Actualizar el saldo” y verificar que puede sustentarse en la arquitectura definida o hacer el ajuste de ésta. Detallar el modelo de clases con las clases de diseño. Modificar los diagramas de interacción. Realizar un modelo de la interfaz para el uso del cajero automático. Integrar el dispositivo lectura de tarjeta con el sistema. Elaborar un documento con la descripción del código fuente generado para el software del sistema del cajero automático. Plan de pruebas para la transición. Revisar los controles de la validación del cliente. Realizar la prueba del caso de uso de “Retirar efectivo”. Revisión y ajuste de controles para la actualización del saldo y dispensar el efectivo. Realizar pruebas integrales. Simular fallas en la comunicación con el servidor del Banco. Ajustar la versión beta del software. Elaborar la versión final del producto.

Tabla Nº 1. Posible marco de trabajo del sistema de cajero automático en el marco del proceso unificado.

Note en este ejemplo, cómo en las fases iniciales se hace un gran esfuerzo por identificar un concepto general del sistema, sus aspectos claves y los riesgos más importantes, entre otros aspectos. El trabajo posterior irá arrojando resultados concretos que son verificables por parte del usuario, a la vez que va incrementándose y refinándose la solución que se elabora. En otras palabras, el

38

esfuerzo converge a una solución de ingeniería que resulta adecuada a las necesidades del cliente. También véase que muchas de las iteraciones combinan actividades de requerimientos, análisis, diseño, implementación y pruebas. Cada fase del UP debe generar lo que se denomina un hito. Esos hitos son los productos finales de cada fase. Los hitos para cada una de ellas son: Inicio. Objetivos del producto. Elaboración. Arquitectura del producto. Construcción. Funcionalidad operativa inicial. Transición. Versión final. En nuestro ejemplo, la última iteración de cada fase muestra los productos que representan el hito esperado en el sistema del cajero automático.

Comentarios finales sobre el UP Un proyecto en la visión del UP, si bien la gente que integra el equipo de trabajo tiene roles específicos, no debería verse con una frontera “clásica” de clientes por un lado e ingenieros de software por otro. De hecho, mi experiencia personal me ha demostrado que una integración en equipo donde, tanto los clientes, como el personal de pruebas y los ingenieros se sientan responsables y “propietarios” del producto final en su buen resultado, es mucho más productivo. Laudon (Laudon, 2005) nos refiere que los sistemas de información son una combinación de aspectos técnicos y sociales. Esto nos debería indicar que ciertamente el proceso de construcción debe tener este carácter también. Y el UP aboga, precisamente, por un enfoque donde los usuarios son protagonistas del proyecto. La visión del UP debe hacernos entender, como ingenieros de software, que debemos estar abiertos al cambio, y dispuestos a responder con agilidad a éste en la sucesión de iteraciones. La visión tradicional nos ha hecho pensar que los proyectos tienen una forma en que, al inicio, todo debe estar definido y que, a partir de ello nos vemos algunos meses más tarde con el cliente y que sobre esa base, cualquier cambio es motivo de angustia, enojo, reajuste de contratos u otros problemas. Ciertamente, el desarrollo de herramientas que permiten ir modelando gráficamente la solución de software, agiliza el trabajo de los ingenieros y, en ese sentido, pueden responder de forma más eficiente al proceso que requieren los clientes. Tales herramientas aprovechan la estandarización metodológica lograda por el A/DOO y apoyada por la notación UML, la cual puede materializarse en lenguajes de programación orientados a objetos utilizando, incluso, generadores de código, los cuales, a partir del modelo creado, genera el código base para

39

lenguajes como JAVA, C# u otros. Gracias a ello, las fronteras entre las actividades fundamentales de la ingeniería de software (identificadas en el UP como identificación de requerimientos, análisis, diseño, implementación y pruebas) se tornan cada vez más tenues. Paralelamente, a medida que vamos modelando el análisis, se están creando y haciendo parte de los modelos del diseño y estos modelos son directamente traducibles a un lenguaje de programación.

UML y el UP El Lenguaje Unificado de Modelación (o UML, por sus siglas en inglés), como lo hemos mencionado al comienzo de esta obra, es una familia de diagramas orientados a apoyar el proceso de A/DOO. Vamos a ver, igualmente, que se utiliza para representar casos de uso, clases, la interacción entre objetos de una clase, la configuración de un sistema, entre otras muchas aplicaciones. UML es el resultado de un acuerdo entre varios precursores del A/DOO en dotar esta metodología de una notación estándar. El UP, al basarse en las ventajas del paradigma de orientación a objetos, se apoya -a su vez- en la notación que proporciona el UML. Conforme vayamos avanzando en el texto, iremos introduciendo los diagramas que nos apoyan en cada parte de la teoría que vaya desarrollándose. CASOS DE USO: LA GUÍA DEL PROCESO Como punto de partida del proceso de construcción de software, identificar y definir los casos de uso nos ayudará a desarrollar eficientemente un proyecto, considerando siempre las necesidades de los usuarios del sistema. Los casos de uso se observan como objetivos y funcionalidades esperadas de los distintos actores que estarán interactuando con el software que se crea. Al considerar el UP (que es un proceso guiado por casos de uso), se espera, por lo tanto, que los esfuerzos que se realizan estén comprendidos en un marco de trabajo que se haya definido de acuerdo a lo que se ha identificado por parte de los clientes, en cuanto a los objetivos que deben cumplirse.

40

Cómo identificar los casos de uso de un sistema Al inicio del proyecto, tal como se ha visto anteriormente, deberá hacerse un esfuerzo importante para poder identificar los casos de uso del sistema. Para ilustrar los conceptos que se desarrollarán seguidamente, se estará utilizando el ejemplo de una biblioteca de una universidad que da servicio a estudiantes, docentes y demás funcionarios de ésta. Seguidamente vamos a recordar cómo se lleva a cabo el proceso de préstamo de un libro en esta biblioteca universitaria que se usará de ejemplo, como punto de partida para ilustrar los conceptos que vamos a desarrollar en este apartado del texto. El usuario puede consultar la lista de materiales bibliográficos que hay disponibles. Esos materiales pueden ser: libros, revistas, periódicos, videos, etc. Producto de la consulta, el usuario puede averiguar si el material está disponible para préstamo, el tipo de restricción que hay para prestarlo, así como si se le permite llevárselo fuera de la biblioteca o bien si es un material para ser consultado únicamente dentro del recinto de la Biblioteca. En el caso de los libros, si no es material restringido, la persona interesada puede ir a los estantes y ubicar el libro, o solicitar la ayuda de un bibliotecario. En el caso de los libros para sala, revistas y videos, el usuario deberá ser atendido por un bibliotecario, para que ubique el material. Para realizar el préstamo, el bibliotecario lee los datos del material solicitado con un lector de códigos de barra. Posteriormente asigna el tiempo de préstamo, dependiendo de las restricciones del material: Si el material puede prestarse fuera de la biblioteca, el bibliotecario asignará 3, 5, 7 ó 14 días, de acuerdo con la demanda de uso. A mayor demanda, menos días se prestaría. Si el material es de uso exclusivo dentro de la biblioteca, se asignarán 4 horas de préstamo en sala. Además, para poder prestar un material, debe comprobarse que el usuario no tenga cargos por morosidad. De ser así, se le impide el préstamo fuera de sala y solo podrá consultar el material dentro de la biblioteca. Un cargo por morosidad se genera en el proceso de devolución del material prestado. Cuando el usuario lo devuelve, se corrobora si que lo está entregando lo hace dentro del plazo establecido. De lo contrario, la biblioteca genera el cargo. El usuario puede cancelar sus deudas en la biblioteca. Esta última genera,

41

regularmente, estados financieros para reflejar los trámites de morosidad generados y para identificar cuáles no han sido aún cancelados. Al buscar los casos de uso de un sistema, debemos plantearnos cuáles son sus objetivos, bajo qué condiciones pueden lograrse y quiénes intervienen en su ejecución. Los objetivos son importantes, porque nos ayudan a identificar claramente qué es lo que persigue el sistema. En nuestro caso: ¿buscará el sistema manejar la base bibliográfica de la biblioteca, con el registro del material, sus autores, editores, la copia de cada uno de éstos? ¿Tendrá que representarse la complejidad de la información que representa un libro o cualquier material bibliográfico para cumplir con los objetivos del sistema? Pareciera que este no es el caso. Nuestro asunto se limita a poder manejar lo referente a los préstamos de un material (que corresponde al objetivo del sistema que hemos tomado como ejemplo), por lo cual, las acciones por desarrollar deben limitarse a ello. Claro está, este subsistema deberá comunicarse con el sistema bibliográfico de la biblioteca, para poder referenciar el material que se tramite. Debe reconocerse en la descripción del sistema, algunas acciones importantes que pueden resaltarse, tales como: ƒ ƒ ƒ ƒ ƒ ƒ ƒ

Consultar disponibilidad de material bibliográfico por parte del usuario. Leer datos del material bibliográfico, por parte del bibliotecario. Consultar morosidad del usuario, por parte del bibliotecario. Registrar la acción de préstamo, por parte del bibliotecario. Registrar la acción de devolución, por parte del bibliotecario. Generar un registro de morosidad, al procesarse la devolución, por parte del bibliotecario. Procesar registros de morosidad, por parte del Sistema Financiero.

Todas estas acciones están enmarcadas dentro del objetivo del sistema de brindar y administrar el servicio de préstamo de material bibliográfico en esa universidad. Note igualmente que, además de enumerarse esas acciones, a la par se está especificando quién hace la acción. En el fondo, lo que se está tratando de identificar, son los actores del sistema, a los que nos referiremos a continuación.

42

Los actores del sistema De acuerdo con Booch et al (2001), los actores son el entorno del sistema. Con ello se hace referencia a que es todo “ente” que interactuará con el sistema. Estos actores pueden ser personas, otros sistemas, hardware etc. Un actor asume un rol en el entorno del sistema. Es importante indicar que dicho rol puede ser asumido por distintos elementos físicos. Más claramente, en el caso de las personas, si por ejemplo Pedro Pérez Pereira es bibliotecario en el sistema que especificamos, igualmente podría ser usuario en el momento en el que éste solicite el préstamo de un material para ser consultado por él mismo en su casa. Como hemos podido observar, los actores persiguen distintos objetivos dentro del sistema. Por ejemplo, para un bibliotecario, su objetivo sería prestar material, registrar las devoluciones, comprobar que los morosos no podrán tener servicio hasta tanto no cumplan con los requisitos exigidos para tal efecto, etc. Un usuario, por su parte, podrá consultar el catálogo de material y, mediante la intermediación de un bibliotecario, podrá recibir préstamos del servicio de bibliotecas. El Sistema Financiero podrá conseguir los registros contables relativos a las cuentas por cobrar y los registros de los pagos realizados por los usuarios morosos. Todos esos objetivos se logran a través de los casos de uso que se desarrollarán en el sistema. De ello estaremos hablando a continuación.

Casos de uso: cómo se visualizan Hemos hablado previamente de los casos de uso. Hemos dicho que se trata de algo así como “historias” de lo que ocurre en el sistema. El sentido de afirmar que son historias, se debe a que éstos tienen la especificación de lo que el usuario desea del sistema. Por lo tanto, es importante que quedemos con este concepto: un caso de uso es la descripción de lo que el usuario desea del sistema. El proceso de identificar casos de uso, puede apoyarse visualizándolos “espacialmente”. En UML, lo anterior se logra mediante el desarrollo de un diagrama de casos de uso. Ello puede ser un ejercicio en el cual, conforme se comienzan a identificar los actores, los objetivos y las funcionalidades del sistema, se procede a plasmarlos gráficamente. Un diagrama consiste en colocar en él los actores y los casos con los que éstos interactúan. En la siguiente figura se muestra un ejemplo de un diagrama de éste

43

tipo. Este ejemplo no pertenece a ningún ámbito de ningún problema. En éste simplemente ilustramos la notación utilizada. Observe que los casos de uso se representan a través de un óvalo y los actores mediante la figura de una persona (que por suerte no es nada compleja: es lo que aprendemos a dibujar en la escuela primaria). La interacción entre el actor y un caso de uso en particular se expresa por medio de una línea. Como puede notar, esto es muy sencillo. Sin embargo, esa sencillez es una forma muy poderosa de poder corroborar entre el cliente y un ingeniero lo que se requiere, en cuanto a funcionalidades de un sistema, dado que la comunicación, usando un diagrama así, puede realizarse de una forma muy simple.

Caso de uso 1

Actor 1

Caso de uso 2

Caso de uso 3 Actor 2

Figura 6. Un diagrama de casos de uso.

En el caso de nuestro ejemplo de préstamos de una biblioteca, vamos a procurar tener claros los objetivos, las funcionalidades y los actores que están involucrados en su desarrollo, precisamente mediante la actividad de especificar los casos de uso. Algo importante que debe considerarse antes de entrar en mayores detalles, es que la esencia de los casos de uso se basa en escribirlos, es decir, en especificarlos. El diagrama es una ayuda visual muy importante para entender, o poder plasmar el entorno del sistema y las funcionalidades esperadas. No

44

obstante, al escribir, podemos medir si realmente estamos entendiendo los objetivos del sistema. Usted y yo, en general, podemos escribir acerca de algo con propiedad, si logramos comprender sobre lo que estamos escribiendo. Así que no tema. Muchas veces podemos toparnos ante actitudes que puedan esbozar una voz parecida a “¿para qué escribe tanto?”, tal vez creyendo que lo importante es diagramar clases o escribir código de programación. Considerando los objetivos y funcionalidades detalladas para nuestro ejemplo del sistema de administración de préstamos de la biblioteca, nos sería fácil esbozar el siguiente diagrama.

Consultar Morosidad Usuario

Sistema Bibliotecario

Registrar Préstamo

Bibliotecario

Usuario

Leer Datos Material Consultar Material Bibliográfico

Registrar Devolución Registrar Morosidad

Sistema Financiero Registrar Devolución con Morosidad

Procesar registros de morosidad

Figura 7. Diagrama de casos de uso para la administración de préstamos de la biblioteca universitaria.

45

Hay varias cosas que debemos analizar de la figura 7 anterior. En primera instancia, note cómo todas las funcionalidades que listamos previamente aparecen como casos de uso del sistema. También observe cómo aparecen cuatro actores, los cuales fueron identificados, también previamente, relacionados con la funcionalidad: el Bibliotecario, el Usuario, el Sistema Bibliotecario y el Sistema Financiero. Estos últimos se refieren a actores que no son personas. Ahora los actores interactúan con el sistema a través de los casos de uso. En este caso, el Bibliotecario interactúa con los casos de uso de Registrar Préstamo y Registrar Devolución. El Usuario lo hará a través de Consultar Material Bibliográfico. El Sistema Financiero lo hará mediante el caso de Procesar Registros de Morosidad, y el Sistema Bibliotecario apoyará los procesos de Consulta de Material Bibliográfico y Leer Datos Material.

Relaciones entre casos de uso En la Figura 7 usted podrá notar que algunos casos de uso se relacionan entre sí. Un primer tipo de relación se establece en el sentido de que, para poder realizar el objetivo planteado para un caso de uso, necesita usarse otro objetivo. Este tipo de relación se denomina “uses”. Véase en el diagrama varios ejemplos de ello. Uno de ellos puede ser el caso de que, para poder registrar un préstamo, necesita leerse de cuál material bibliográfico se trata. Adicionalmente, puede existir otro tipo de relación en el cual, un caso de uso es la especialización de otro. Por ejemplo, Registrar Devolución con Morosidad es, en esencia, lo mismo que Registrar Devolución, pero incluye la capacidad de poder registrar un cargo de morosidad por una devolución tardía. Esta relación se denomina “extends”. Realizar un diagrama de casos de uso nos ayuda a visualizar, tal y como se mencionó anteriormente, de qué forma los usuarios (actores) interactuarán con el sistema.

Especificación básica de casos de uso En el proceso de definición de los casos de uso, debe establecerse una especificación de lo que hace cada uno de éstos. Siguiendo con el ejemplo de la administración de préstamos de la biblioteca, se desarrollará una especificación básica de los casos de uso involucrados en este sistema. Recordemos que una

46

especificación básica consiste en indicar, en pocas palabras, aspectos relevantes de los casos de uso. Veámoslo en el siguiente ejemplo. Caso de uso

Consultar material bibliográfico

Actor (es)

Usuario, Sistema bibliotecario

Descripción. Un usuario consulta la existencia de un material bibliográfico de su interés. El Sistema Bibliotecario apoya la búsqueda de este material a través de parámetros como título, autor, palabras calve, entre otros. Además, puede visualizar qué restricciones de préstamo tiene este material y la disponibilidad de copias. En el caso de que la restricción del material indique que no puede sacarse de la biblioteca, el sistema proporcionará el código del material para que sea utilizado posteriormente por el bibliotecario en ventanilla. Caso de uso

Registrar préstamo

Actor (es) Bibliotecario Descripción. El bibliotecario pide al usuario su identificación y consulta el estado de morosidad de la persona. Si está libre de cargos, lee los datos de un material bibliográfico que será prestado. Los datos se leen a través de una etiqueta de código de barras que viene en el material. El sistema, de acuerdo con las restricciones y la frecuencia de uso del material, indica el tiempo de préstamo conveniente para éste. El bibliotecario registra finalmente los datos del material prestado. Caso de uso Actor (es)

Consultar morosidad usuario Bibliotecario

Descripción. Al realizar el trámite de un préstamo, el bibliotecario debe consultar el estado de la morosidad de un usuario. Esta consulta deberá devolver una indicación al bibliotecario y al resto del proceso, si puede continuarse o no puede seguirse con el trámite del préstamo. Caso de uso

Leer datos del material

Actor (es)

Bibliotecario, Sistema Bibliotecario

Descripción. Al realizar el trámite del material bibliográfico, bien sea para préstamo o para devolución, el bibliotecario usa un código de barras para poder leer los datos de dicho material.

47

Caso de uso

Registrar devolución

Actor (es)

Bibliotecario

Descripción. El bibliotecario, una vez que lee los datos del material devuelto, si no hay morosidad, procede a dar por devuelto dicho material.

Caso de uso

Registrar devolución con morosidad

Actor (es)

Bibliotecario

Descripción. Al procesar una devolución, luego de leerse los datos del material prestado, si se detecta que el material está sujeto a morosidad, se habilita un proceso para tramitar la multa que el usuario debe pagar. El sistema calcula dicha multa y el bibliotecario termina de registrar los datos de la devolución y de la multa para el usuario.

Caso de uso

Registrar morosidad

Actor (es)

Bibliotecario

Descripción. Se proporcionan los datos del material bibliográfico, el usuario que incurre en morosidad y la multa asociada, para registrar la multa por cobrar y el estado de moroso para el usuario

Caso de uso

Procesar registros de morosidad

Actor (es)

Sistema financiero

Descripción. Procesa los registros que debe poner al cobro y los que ya ha pagado el usuario. Con éstos últimos, el sistema chequea si debe quitar el estado de moroso a dicho usuario.

48

Logrado este avance en la especificación, consigue tenerse una mejor comprensión de lo que debe realizar el sistema. Además, pueden visualizarse cuáles son críticos para el desarrollo, por su rol dentro del sistema o por las complejidades que acarrea, y, por lo tanto, cuáles son de mayor riesgo. Estos últimos son los que deberán ser tratados con especial cuidado. Siguiendo este razonamiento, de aquí en adelante vamos a enfocarnos en dos aspectos críticos relacionados con el ejemplo que estamos desarrollando: el préstamo y la devolución de libros. Estos casos de uso, además, relacionan muchos otros que también son importantes de detallar. Para los que no se especifiquen, usted ya tendrá suficiente guía de cómo podría profundizar más en ellos. En este caso también consideramos que al detallar las funcionalidades de préstamo y la devolución, prácticamente se estaría definiendo toda la arquitectura necesaria para sostener el sistema, esto es, también, todos los casos de uso. Si no fuera así… ¡ES PARTE DE LA NATURALEZA DEL UP! Quizás al incorporar la definición de otros casos de uso, algunos ajustes, seguramente menores, habrá que realizar en la arquitectura del sistema.

Especificación detallada de casos de uso La especificación básica debería cerrar un punto del proyecto en la cual ya podemos tener resultados en cuanto a identificar actores del sistema, los objetivos, las funcionalidades y comprender cada una de ellas. No obstante, en mucho, la comprensión de un trabajo de software debe ir convergiendo de lo general a lo específico. En ese sentido también podemos ir descubriendo detalles cada vez más importantes y reveladores del problema por solucionar. Es así como, en un segundo momento de especificación de casos de uso, debemos detallar -aún más- su especificación buscando, por una parte, descubrir mayor información en cuanto a las necesidades y consecuencias en el sistema de la ejecución de éstos y, por otra parte, intentando que proporcionen una guía para poder definir varios aspectos de la arquitectura y del proceso general de diseño e implementación del software. Esta especificación es crucial en el contexto que estamos trabajando. Recuerde que el UP es guiado por los casos de uso.

49

Elementos de una especificación detallada Booch et al. (2001) sugieren estructurar la especificación de los casos de uso con los siguientes elementos y detalles: Las condiciones previas que deben cumplirse para que el caso de uso pueda ejecutarse. Una secuencia, normalmente ordenada y numerada de los pasos que se dan dentro del caso de uso. El primer paso debería indicar cómo y cuándo empieza el caso de uso. En cada paso deberá indicarse, cuando sea conveniente, qué acciones no son permitidas y qué aspectos son responsabilidad del actor y cuáles son del sistema. Veamos cómo terminan los casos de uso. Las acciones alternativas que puedan ocurrir en la ejecución de los casos de uso, producto de situaciones anómalas (excepciones) u otras consideraciones. El estado en que queda el sistema y las acciones generadas en éste, como consecuencia de la ejecución del caso de uso (visto como condiciones posteriores). Otros autores pueden sugerir incluir alguna otra información que enriquezca (o complique) la especificación de un caso de uso detallado. Vamos a valernos de estos elementos que proporcionan una idea clara y completa de lo que es esta descripción. Esto último no contradice el hecho de que en el contexto específico de una organización puedan definirse variaciones para que se desarrolle el proyecto a la conveniencia de un grupo o equipo de proyecto. Vamos a desarrollar la especificación de uno de los casos de uso del sistema de administración de préstamos de libros, como un primer ejemplo que ilustre lo que venimos comentando en los apartados previos. Para tal caso estaremos analizando el caso de uso de “Registrar Préstamo”. Vamos a recordar por un momento la especificación básica de éste. Caso de uso Actor (es)

Registrar préstamo Bibliotecario

Descripción. El bibliotecario pide al usuario su identificación y consulta el estado de morosidad de la persona. Si no se identifica como moroso, lee los datos del material bibliográfico que será prestado. Los datos se leen a través de una etiqueta de código de barras que viene en el material. El sistema, de acuerdo a las restricciones y la frecuencia de uso del material, indica el tiempo de préstamo conveniente para éste. El bibliotecario registra finalmente los datos del material prestado.

50

Con esta base, empezar a desarrollar la especificación detallada del caso de uso en cuestión. En primer lugar, ¿podemos esbozar algunas condiciones previas producto de la especificación básica del objetivo? ¿Nos es fácil definir qué requerirá el bibliotecario para poder desarrollar el caso de uso? En este caso contamos con algunos aspectos necesarios para poder ejecutar el caso de uso. En primer lugar, el bibliotecario deberá tener en sus manos el material por prestar, ya sea que el usuario se lo haya proporcionado, o bien que él mismo haya tenido que buscarlo, dado que es de préstamo restringido. Además, el usuario debe contar con la identificación que lo habilite para poder usar el servicio de biblioteca. Quizás podamos esbozar algunas otras condiciones, pero éstas son las que son críticas para poder ejecutar el préstamo. De igual forma, podemos pensar cuáles son las condiciones posteriores que deben producirse al darse el caso de uso. En definitiva, deber haberse creado un registro de préstamo asociado al usuario que solicitó el material, indicando, además, la fecha y el material prestado. A su vez, el material debe quedar con el estado de “prestado”. La secuencia de pasos podría irse construyendo de la siguiente forma. - El caso de uso comienza cuando el Bibliotecario ingresa al sistema la identificación del Usuario. El Sistema le indica si el Usuario es válido. - El Sistema revela, además, si el Usuario tiene algún registro de morosidad. - Una vez comprobados los pasos anteriores, el Bibliotecario lee del Sistema Bibliotecario, la información del material que va a prestarse, a través de un lector de código de barras. En ningún caso puede prestarse otra copia del mismo material al mismo usuario, lo cual se comprueba por parte del Sistema cuando se hace esta lectura. - El Sistema indica si el material puede ser prestado solo para uso interno de la biblioteca y el tiempo que puede ser prestado en cualquier caso. - El Bibliotecario registra el préstamo del material y el caso de uso termina. Note que, en primer lugar, se está cumpliendo con el objetivo de registrar el préstamo. Además, se están especificando algunos controles importantes, como comprobar que el usuario esté afiliado a la biblioteca, que no tenga morosidad,

51

que no se le preste otra copia del mismo material y si ese mismo material es restringido o no, determinando dónde y cuánto puede ser prestado éste. Los pasos anteriores los vamos a denominar como el curso normal de eventos, es decir, que esos pasos son los que se dan en la ejecución normal del caso de uso. Esto también autores como Larman (2003) y Pressman (2006) lo llaman escenario. Usaremos indistintamente ambas denominaciones. Al pensar que existe un curso normal de eventos, da cabida a especular que podrían existir otras alternativas de ejecutar el caso de uso. Esto los llamaremos cursos alternativos y se especifican refiriéndose a un paso que se ha numerado en el escenario del caso de uso. Así tendríamos que ver, paso por paso, qué podría ser un curso alternativo en cada uno de éstos pasos. En el paso 1 se espera que el sistema compruebe que el Usuario no está registrado en la Biblioteca, por lo cual el caso de uso termina. Esto significa que no pueden darse los siguientes pasos después del 1. En el paso 2, si el Usuario está moroso, el caso de uso termina. En el paso 3, un hecho que podría presentarse es que el código de barras del libro esté ilegible, por lo cual el Bibliotecario deba ingresar este directamente en un campo de edición de la pantalla. En el paso 3, también, puede comprobarse que el Usuario ya tenga una copia del mismo material asignado en otro préstamo, por lo cual el caso de uso termina. En el paso 4, luego de indicarle al Usuario las restricciones del préstamo, éste puede decidir no aceptar las condiciones, por lo cual el Bibliotecario cancela la ejecución del caso de uso. Una plantilla de esta descripción detallada del caso de uso, puede sugerirse que sea de la siguiente forma.

52

Casos de Uso Objetivo Actores Condiciones previas Escenario

Excepciones o cursos alternativos

Condiciones posteriores

Registrar préstamo Registrar la información del préstamo de un material bibliográfico que se hace a un usuario de la biblioteca de la Universidad Bibliotecario El Bibliotecario deberá tener en sus manos el material a prestar, ya sea que el usuario se lo haya proporcionado, o bien que el Bibliotecario haya tenido que buscarlo, dado que es de préstamo restringido. Además, debe contar con la identificación del usuario que lo habilite para poder usar el servicio de la biblioteca. El caso de uso comienza cuando el Bibliotecario ingresa al Sistema la identificación del Usuario. El Sistema le indica si el Usuario es válido. El Sistema, le indica, además, si el Usuario tiene algún registro de morosidad. Una vez comprobados los pasos anteriores, el Bibliotecario lee del Sistema Bibliotecario la información del material que va a prestarse, a través de un lector de código de barras. En ningún caso puede prestarse otra copia del mismo material al mismo Usuario, lo cual se comprueba por parte del Sistema cuando se hace esta lectura. El Sistema indica si el material puede ser prestado solo para uso interno de la Biblioteca y el tiempo que puede ser prestado en cualquier caso. El Bibliotecario registra el préstamo del material y el caso de uso termina. En el paso 1, de comprobarse que el Usuario no está registrado en la biblioteca, el caso de uso termina. En el paso 2, si el Usuario está moroso, el caso de uso termina. En el paso 3, si el código de barras del libro esté ilegible, el Bibliotecario deberá ingresar este directamente en un campo de edición de la pantalla. En el paso 3, de comprobarse que el Usuario ya tiene una copia del mismo material asignado en otro préstamo, el caso de uso termina. En el paso 4, luego de indicarle al Usuario las restricciones del préstamo, éste puede decidir no aceptar las condiciones, por lo cual el Bibliotecario termina la ejecución del caso de uso. De cumplirse el paso 5, el Sistema guarda el registro del préstamo efectuado al Usuario. El material debe quedar en estado de “prestado”.

Observe que la información de esta especificación va, ciertamente, logrando más rico el detalle de la descripción, haciendo resaltar controles, responsabilidades del sistema y de los actores, así como condiciones que deben darse previa y posteriormente al préstamo. Pero otro elemento poderoso es que… está escrito en lenguaje natural, por lo que puede ser validado junto con el cliente del sistema. ¡EXCELENTE! De igual forma podemos proceder a detallar el caso de uso, cuando se trata de la devolución de un libro. En el análisis inicial reconocimos dos casos de uso para esta función: Registrar Devolución y Registrar Devolución con Morosidad.

53

Revisemos la especificación básica de estos casos de uso. Caso de uso

Registrar devolución

Actor (es)

Bibliotecario

Descripción. El Bibliotecario, una vez que lee los datos del material devuelto, si no hay morosidad, procede a dar por devuelto dicho material.

Caso de uso Registrar devolución con morosidad Actor (es)

Bibliotecario

Descripción. Al procesar una devolución, luego de leerse los datos del material prestado, si se detecta que el material está sujeto a morosidad, se habilita un proceso para tramitar la multa que el Usuario debe pagar. El sistema calcula dicha multa y el Bibliotecario termina de registrar los datos de la devolución y de la multa para el Usuario.

Al examinar éstas especificaciones podríamos pensar que “simplemente” un condicional diferenciaría una de otra (chequear la condición de morosidad) y que podría manejarse como una excepción en la descripción detallada del escenario de alguno de los dos casos de uso. No obstante, los mecanismos que se desatan en la devolución con morosidad, como podrá observarse de la descripción del caso de uso, pueden ser mucho más complejos, como calcular la multa, registrar un registro de morosidad, entre otros. Por lo tanto, podría ser más nítido especificar uno y otro separadamente. De igual forma, adelantándonos un poco en el tiempo del proyecto, recuerde que, gracias al paradigma de orientación a objetos, tenemos un recurso llamado polimorfismo que nos puede ayudar a definir, en el momento de diseñar la solución, dos métodos con nombres iguales. Más adelante, cuando definamos la arquitectura, retomaremos este aspecto de la solución. A continuación veremos la definición de estos casos de uso, de forma detallada. Una devolución, como precondición, debería haber comprobado la morosidad del material, de tal forma que el sistema sepa cuál caso de uso debería usarse. En

54

tal caso no le estamos “cargando” a ninguno de los casos de uso la responsabilidad de saber cuál debe ejecutarse. No obstante, tal acción no la observaremos directamente reflejada en el diagrama de casos de uso. Alguien nos ayudará en su momento. Ese alguien será una clase de gestión, la cual estudiaremos con mayor detalle más adelante. Otra condición previa que puede parecer obvia, pero que necesitamos controlar (a veces tendemos a “obviar lo obvio”), es que el material por procesar debe estar en condición de “prestado”. En cualquiera de los dos casos, al final debe registrarse el material como “devuelto”. Este es el “compromiso” o “contrato” de estos casos de uso. El escenario de los casos de uso será el que maneje las acciones del registro de la devolución. Deben tomarse en cuenta las responsabilidades compartidas entre lo que hace el actor y lo que responde el sistema en cada caso, cuando sea pertinente. Vamos a escribir el detalle de los dos casos de uso y usted podrá observarlos y seguramente familiarizarse más con esta forma de especificación. Caso de uso

Registrar devolución

Objetivo

Registrar la devolución de un material bibliográfico previamente prestado.

Actores

Bibliotecario

Condiciones previas

En la comprobación de la morosidad del préstamo, este debió haber estado “sin morosidad”. El material debe tener el estado de “prestado”.

Escenario

El caso de uso empieza cuando el Bibliotecario introduce el código del material que fue prestado mediante el código de barras. El sistema registra la devolución e indica: “La devolución del (Libro / Revista / Video) xxxx fue registrada con éxito”. En el paso 1, si el código de barras del libro está ilegible, el Bibliotecario deberá ingresar este directamente en un campo de edición de la pantalla. De cumplirse el paso 2, el sistema actualiza el registro del préstamo, grabando la fecha de devolución y cambiando el estado del material a “devuelto” y ubicando el estado del préstamo en “Cerrado normal”.

Excepciones o cursos alternativos Condiciones posteriores

55

Mientras tanto, para el caso de uso de “Registrar devolución con morosidad” tendríamos lo siguiente. Caso de uso Objetivo Actores Condiciones previas Escenario

Excepciones o cursos alternativos Condiciones posteriores

Registrar devolución con morosidad Registrar la devolución de un material bibliográfico previamente prestado, el cual tiene morosidad asociada Bibliotecario En la comprobación de la morosidad del préstamo, este debió haber estado “con morosidad”. El material debe tener el estado de “prestado”. El caso de uso empieza cuando el Bibliotecario introduce el código del material que fue prestado mediante el código de barras. El sistema calcula el monto correspondiente por morosidad, de acuerdo con el tipo de material, las restricciones de uso y el retraso en tiempo. El Usuario procede a dar “Aceptar” al registro de la devolución, visualizando el monto del cobro que se le realizará al Usuario. El sistema registra la devolución creando a su vez un registro de morosidad. En el paso 1, si el código de barras del libro esté ilegible, el Bibliotecario deberá ingresar este directamente en un campo de edición de la pantalla. De cumplirse el paso 4, el sistema actualiza el registro del préstamo, grabando la fecha de devolución y cambiando el estado del material a “devuelto” y colocando el estado del préstamo en “Cerrado con morosidad”.

Finalmente, observe cómo los casos de uso sirven para poder especificar de una forma relativamente simple, pero poderosa, los objetivos que tiene un sistema, “expresando” las funcionalidades que se esperan de él. Las funcionalidades vienen a ser verificadas por los clientes del sistema y las pueden realizar cómodamente, puesto que están escritas en un lenguaje natural. Además, podemos asegurarnos que lo que vayamos a desarrollar esté aprobado y comprobado por los interesados. Veremos, en los siguientes capítulos, que la buena definición de los casos de uso será fundamental para guiar el proceso de desarrollo de la ingeniería de software en lo que se refiere al análisis y diseño de la arquitectura.

56

EJERCICIOS DE AUTOEVALUACIÓN 1.

Mencione y ejemplifique los dos fundamentos de la abstracción del paradigma de orientación a objetos.

2.

¿Qué son los conceptos de identidad y estado de un objeto?

3.

¿Qué es una clase? encapsulamiento?

4.

Construya una jerarquía de clases a partir de la clasificación de artículos en una tienda de departamentos. Explique mediante esta clasificación el concepto de herencia y, además, ejemplifique el concepto de polimorfismo.

5.

Explique qué es el Proceso Unificado. Para esta explicación básese en las tres características propias del Proceso Unificado.

6.

Explique los conceptos de caso de uso y de actor. De ejemplos distintos a los vistos en el libro sobre casos de uso en donde se pueda tener representandos actores que son y no son personas.

7.

Para el problema que se le presenta a continuación, elabore lo siguiente: -

-

¿Cómo se relaciona el concepto de clase con el

El diagrama de casos de uso. La descripción breve de los casos de uso. La identificación los casos de uso más riesgosos. Justificar por qué usted los considera así. La estrategia de cómo irá desarrollando los casos de uso usando Proceso Unificado (por ejemplo, con cuáles casos de uso irá empezando, en cuáles fases los irá especificando, qué ira obteniendo del desarrollo de éstos). La elaboración en detalle de uno de los casos de uso identificados como riesgosos.

La empresa de seguros médicos “Aseguro”, le ha contratado para desarrollar un software que permita apoyar la administración de las actividades de éste. Para ello, esta empresa quiere facilitar a clínicas y hospitales, un sitio en Internet que permita acceder a los datos de los asegurados, así como procesar lo referente a los pagos que deben cobrarse por deducible a éstos y los que deben realizarse a hospitales y clínicas como parte de los servicios brindados.

57

Cuando se da una atención, el asegurado debe indicar al recepcionista en el hospital que es beneficiario de “Aseguro”. Éste le muestra su credencial y posteriormente pasa a recibir los servicios médicos del caso. Cuando la atención termina, el hospital le da al asegurado una copia de la factura. El personal administrativo del hospital, en el mismo sitio Web, ingresa los datos y los costos de la atención suministrada a los pacientes. Algunos hospitales han interconectado sus sistemas con los de “Aseguro” para el intercambio electrónico de datos de la atención a pacientes. Con los datos suministrados por el hospital, Aseguro emite los pagos para éstos, además de poner al cobro los montos por deducible para los asegurados.

58

CAPÍTULO

2

EL MODELO CONCEPTUAL DE CLASES: LA EXPRESIÓN DE LOS CONCEPTOS DEL PROBLEMA

SUMARIO CONSIDERACIONES PRELIMINARES

DEFINICIÓN DEL MODELO CONCEPTUAL Modelando los conceptos Categorías de clases conceptuales

CASOS DE USO E IDENTIFICACIÓN DE CLASES CONCEPTUALES DIFERENCIAR CONCEPTOS QUE SON CLASES Y CONCEPTOS QUE SON ATRIBUTOS RELACIONES CONCEPTUALES ENTRE CLASES Cardinalidad de las relaciones Nombre de las relaciones Relaciones múltiples entre clases Relaciones hacia la misma clase Especificación de conceptos en el modelo de clases

AÑADIENDO ATRIBUTOS AL MODELO CONCEPTUAL DEFINIENDO OPERACIONES EN EL MODELO

59

OBJETIVOS Una vez que usted estudie este capítulo, podrá llevar a cabo cada una de las siguientes actividades de aprendizaje, que le servirán para comprobar cuánto ha aprendido de este tema - Justificar la importancia de los casos de uso como forma de “guiar el desarrollo” en el Proceso Unificado. - Identificar, a partir de los casos de uso, conceptos claves para la identificación y desarrollo de clases conceptuales. - Diferenciar lo que puede ser una clase conceptual de lo que es un atributo dentro de una clase. - Indicar cómo se relacionan las clases entre ellas, identificando, además, un nombre para la relación y su cardinalidad. - Describir que son las relaciones múltiples entre el mismo par de clases. - Identificar relaciones entre la misma clase. - Explicar qué se entiende por especificación de clases y solucionar situaciones de modelaje de clases usando dicho concepto. - Experimentar el proceso iterativo de la definición del modelo conceptual de clases a partir del análisis de un caso de uso y de la incorporación de otros casos de uso en dicho modelo. - A partir del análisis del escenario de los casos de uso, identificar las operaciones o métodos necesarios que deben tener las clases.

60

CONSIDERACIONES PRELIMINARES En este capítulo nos propondremos conocer los trabajos que deben realizarse para poder crear un modelo conceptual de clases. Esto resulta especialmente importante debido a que, por una parte, obtendremos la base para crear los elementos de software que podrán apoyar la implementación de los casos de uso y, por otra parte, serán la guía del trabajo que transforman las abstracciones conceptuales identificadas en clases conceptuales, hacia las clases de diseño las cuales serán las que orientarán el trabajo de codificación que debe realizarse. Por lo tanto, generar un modelo conceptual adecuado, resulta clave en todo el proceso de ingeniería que seguimos en el ADOO. Ya nos hemos referido en el primer capítulo acerca de las clases en el paradigma de orientación a objetos. Si recordamos, allí estudiamos que las clases son creadas con el fin de agrupar todos los objetos que de la abstracción a la cual tratábamos de acercarnos. Por ejemplo, una clase Silla debe identificar todos los objetos de tipo silla que hay en el mundo. Esta primera aproximación que hemos dado a las clases debe ayudarnos ahora. Hay que tener presente que al buscar definir clases, buscamos especificar las características que deben ser comunes a todos los objetos de dicha clase, tanto en sus características vistas como atributos, y en su comportamiento que se expresa como operaciones o métodos. En el ámbito del ADOO tales abstracciones son vistas como los conceptos que se hallan en el espacio del problema que tratamos de solucionar. Para poder ir comprendiendo el proceso de definición de estas clases, vamos a seguir desarrollando el ejemplo referente a nuestro sistema de préstamo bibliotecario. DEFINICIÓN DEL MODELO CONCEPTUAL Recordemos que, en general, nos estamos enfrentando a un proceso evolutivo de definición de software. Los modelos que desarrollemos a través de diagramas UML irán entrando en mayor detalle conforme pasan las iteraciones en las fases del UP. En el capítulo anterior vimos cómo los casos de uso pasan por ese proceso de irse definiendo con mayor detalle, de igual forma sucederá con las clases.

61

En este punto tenemos que considerar lo siguiente. Hay varios tipos de clases dentro de las cuales podemos encontrar las siguientes, de acuerdo con Pressmann (2005):

Clases de análisis o conceptuales. Son las clases producidas a partir de ir modelando las abstracciones y conceptos involucrados en el espacio de una solución. Por ejemplo, en un sistema de ventas, estaremos buscando modelar abstracciones y conceptos como: producto, inventario, factura, entre muchos otros. En este tipo de clases no se busca entrar en mucho detalle, sino más bien, busca identificar, a gran nivel, qué conceptos están involucrados en la solución y cómo se relacionan éstas, modelando los diagramas necesarios para ello.

Clases de negocio. Este tipo de clases da un mayor nivel de refinamiento a las clases de análisis, buscando proveer mayor precisión para la definición del software. Se busca detallar los atributos y las operaciones que deben tener las clases.

Clases de proceso o gestión. Este tipo de clases coordinan acciones que se dan entre clases de negocios para un propósito del software. Por ejemplo, un proceso que coordine una venta, posiblemente tenga que usar objetos involucrados con “factura”, “inventario” y “producto”. Las acciones de esos objetos son administradas por una clase de gestión.

Clases persistentes. Son clases que representan almacenamiento de datos. De igual forma, podemos encontrar en estas clases los servicios para poder grabar, en una base de datos, la información que se maneja en las clases de negocios. Clases de sistema. Son las clases que están especializadas en la interacción con el sistema operativo y los dispositivos de hardware involucrados en la solución.

En este texto vamos a prestar especial atención a las tres primeras clases, pues a través de ellas se conforma, en gran medida, la solución que, como ingenieros de software, debemos crear. Especialmente quiere resaltarse, nuevamente, que la definición de tales clases es un proceso. Recuérdese que, tanto el análisis, como el diseño, presentan una característica importante de refinamiento, el cual se espera que, conforme pasen iteraciones en el proceso de construcción del software, se definan en mayor medida las características de las clases. Y dentro de la clasificación que acabamos de ver, pasar de las clases conceptuales, a las clases de diseño y poder identificar las clases de gestión adecuadas, es parte de ese proceso. Sin embargo este refinamiento es mucho más directo cuando se utiliza el ADOO, usando diagramas como los que provee UML. Veremos, tal como destaca Larman,

62

que las transiciones entre un modelo conceptual, a un modelo de clases de negocio, es un proceso “natural” de dicho refinamiento.

Modelando los conceptos Cuando comenzamos a tratar de elaborar un modelo de clases, debemos saber que no es una tarea fácil. Quizás si se posee mucha experiencia, poder intuir y definir clases se vuelve un proceso muy natural en un ingeniero de software, pero no es simple. Por eso debemos comenzar a realizar esbozos de los conceptos alrededor del dominio del problema que queremos modelar. Por otra parte, también tenemos que considerar que esos conceptos dependen mucho del contexto organizacional o cultural donde se ubiquen. Por ello usted debe estar familiarizado con dicho contexto. Por ejemplo, en la tabla que presentamos a continuación, se muestran algunos conceptos propios de algunos trabajos en los que he participado:

Entorno Comercialización eléctrica Asistencia social Universidad

Conceptos Abonado, Facturación, Medidor, Ciclo de lectura, Ubicación, Ruta de lectura Familia, Beneficios, Subsidios, Medición de pobreza, Resolución, Presupuesto Plan de Estudios, Materias, Cursos, Proyecto de Investigación, Matrícula

Estamos seguros que usted sabe qué significan algunos de esos conceptos y otros seguramente que no. Por lo tanto, debemos asegurarnos, incluso si tuviéramos noción de su significado, de qué es lo que las personas entienden por ellos y qué significan en el contexto en el que se encuentran. Elaborar un diccionario o glosario de esos términos, siempre es una buena práctica. Pero, ¿Cómo podremos comenzar a ubicar esos conceptos? Recordemos que cuando definimos clases, vimos tres partes que las componen: su nombre, sus atributos y sus operaciones o métodos. Cuando comencemos a modelar los conceptos no vamos a detenernos a detallar -a gran nivel- TODOS sus atributos y TODAS sus operaciones, sino que nos concentraremos en identificar, en un nivel muy alto, qué conceptos están involucrados.

63

Posiblemente, podemos definir uno que otro atributo u operación significativa, pero, tal como lo mencionamos, sin abundar en detalles. Un primer ejemplo que quizás le resulte muy familiar. Imagine todo lo que puede pasar en un sistema cuando usted está pagando la compra de víveres, en la caja de un supermercado. ¿Qué conceptos que podrían ser potenciales clases están reuniéndose allí? Usted está viendo que un cajero pasa productos por un lector de códigos de barras, que al mismo tiempo está conformándose el detalle de una factura, que podría estar actualizándose algo como un inventario, quizás el cliente podría estar presentando su tarjeta de cliente frecuente. En este momento podemos hacer una lista de conceptos que pueden ser necesarios para poder modelar la solución: productos, lector de códigos de barras, factura, inventario, cliente, tarjeta. Vea que tales conceptos pueden ser personas (cajero, cliente), o dispositivos (lector de códigos de barra); pueden ser también elementos de información (tarjeta, factura), cosas muy concretas (productos) o también procesos que se llevan a cabo (inventario). Por el momento, no vamos a ir más allá de esbozar algo que podemos intuir del contexto que estamos observando al ver funcionar una caja en un supermercado. Al utilizar una herramienta para diagramar, podemos utilizar el modelo de clases para comenzar a “dibujar” estos conceptos. Eso se muestra en la siguiente figura: Producto

Cajero

Factura

ExistenciaProducto

Cliente

Tarjeta

Venta

Figura 8. Conceptos en un punto de venta de un supermercado.

Note que en la Figura 8 solamente hay una serie de “cajas” las cuales, por el momento, expresan un concepto potencial: Cajero, Producto, Cliente, etc. En el ADOO este es un paso fundamental, pues estamos obteniendo los insumos para ir desarrollando nuestro modelo de clases.

64

Tenemos que tomar en cuenta que estamos tratando con un sistema. Tal como lo mencionábamos en el capítulo anterior, en lo referente al UP, los elementos deben organizarse y combinarse de alguna forma para que puedan expresar la solución que queremos. Como sistema, esas cajas “inconexas” que vemos en la Figura 8, deberían tener alguna relación. Esas relaciones buscan, en primer lugar, tratar de establecer cómo podrían “servirse” unas de otras, es decir, cómo se asocian, cómo colaboran, cómo se organizan para un propósito común: brindar el o los servicios que esperan ofrecerse a través del sistema. Este ejemplo lo hemos venido desarrollando, usando nuestra imaginación: como si de pronto pudiéramos ir adivinando qué hay detrás de algo que nos resulta familiar, por ejemplo, ir al supermercado y ver cómo es un proceso de compras. Sin embargo, ya hemos visto que los objetivos y funcionalidades del sistema pueden expresarse a través de los casos de uso. Entonces, si al final del párrafo transanterior se dice que los elementos se organizan para que el sistema pueda brindar el o los servicios que se esperan ofrecerse, esto ya debe estar manifiesto cuando elaboramos los casos de uso. Es primordial anotar, por lo tanto, que uno de los insumos importantes que podemos tener para identificar clases potenciales, son los casos de uso. A esto volveremos más adelante, cuando retomemos el ejemplo de nuestra biblioteca. Volviendo al caso del punto de venta del supermercado, podemos ver en la siguiente figura, algunas relaciones que podemos visualizar en nuestro modelo conceptual.

65

Producto

Cajero

DESCRIBE ESTADO

CREA Y REGISTRA Factura

DetalleVenta

ExistenciaProducto

INCLUYE ACTUALIZA

SE LE HACE A Cliente

Tarjeta IDENTIFICA

Figura 9. Relaciones en el modelo conceptual.

En la Figura 9 podemos observar cómo los elementos pueden ser descritos, también, en la forma en que se asocian con los otros. Además, podemos darle nombre a esas relaciones. Por ejemplo, Cajero con respecto a la Factura, indica que el primero la crea y la registra en el sistema. Por otra parte, de Factura hacia el Cliente se dice que la primera se le hace para el segundo. La ExistenciaProducto dice que describe el estado del Producto en el sistema del supermercado (por ejemplo cuánto hay del producto, dónde está localizado, etc.). Poder establecer estas relaciones y, además, estar en capacidad de darles nombres, se logrará si comprendemos bien el contexto del problema. La forma que tenemos a mano para poder lograrlo, consiste en ir conociendo los objetivos del sistema, estar al corriente sobre qué es lo que hace para lograr cada uno de éstos objetivos, identificando conceptos y colaboraciones importantes. Es decir, los casos de uso. Que el UP esté guiado por casos de uso y orientado a la arquitectura, no es casualidad. Acá comenzamos a ver cómo convergen. Sigamos desarrollando nuestro ejemplo del sistema de préstamos de la biblioteca para ir descubriendo más aspectos relativos a este proceso.

66

Categorías de clases conceptuales Larman (2005) establece dos estrategias principales para poder identificar clases conceptuales: • •

Utilización de una lista de categorías de clases conceptuales Identificación de frases nominales

Para el primer caso, en la tabla que se incluye a continuación, se presentan las categorías principales propuestas por dicho autor.

Categoría de clase conceptual Ejemplos Objetos tangibles o físicos Libro, Revista Especificaciones, diseños o descripciones de las Especificación del producto (copias de un libro) cosas Lugares Transacciones Líneas de la transacción Roles de la gente Contenedores de otras cosas Cosas en un contenedor Otros sistemas informáticos o dispositivos externos al sistema Organizaciones Hechos Catálogos Registros de finanzas, trabajos, contratos, cuestiones legales Instrumentos y servicios financieros Manuales, documentos, libros

Biblioteca Central, Biblioteca de Sede, Biblioteca de Salud Préstamo, Devolución de un material Cada copia de material prestado en una transacción de Préstamo Usuario, Bibliotecario Estante Libro Sistema financiero Biblioteca Préstamo, Devolución, Mora por devolución Catálogo de materiales bibliográficos Comprobante de préstamo Restricciones al préstamos de libros, Adquisición al por mayor de un libro Procedimiento de mantenimiento del material bibliográfico

Tabla Nº 2. Lista de categorías de clases conceptuales. Adaptado de Larman (2003)

Como ejercicio, del ejemplo de las clases conceptuales del supermercado que vimos en las Figuras 8 y 9 podemos clasificarlas en alguna de las categorías propuestas en la Tabla Nº 2 anterior.

67

ƒ

Cajero, Cliente: Roles de la gente.

ƒ

Factura, Producto, Tarjeta: Objetos tangibles o físicos, Registro de finanzas.

ƒ

Detalle Venta: Líneas de la transacción, Hechos.

ƒ

ExistenciaProducto: especificaciones, diseños o descripciones de las cosas.

La guía que nos da la Tabla Nº 2 nos permite proceder con la identificación de los conceptos que pueden aparecer en el espacio del problema que estamos tratando. De igual forma, Larman nos señala que podemos basarnos en frases nominales, es decir, la que nos provean sustantivos significativos para poder identificar algún concepto. Sin embargo, una frase podría aparecer como ambigua, lo cual, metodológicamente puede ser una debilidad. A mi juicio ambas estrategias no son excluyentes. Tome en cuenta que los casos de uso, en su descripción breve o detallada, proveen información importante mediante frases nominales. A partir de éstas, podríamos fijarnos en la Tabla Nº 2, de categorías propuestas por Larman, para proceder a identificar conceptos. CASOS DE USO E IDENTIFICACIÓN DE CLASES CONCEPTUALES Hemos desarrollado hasta este momento, la especificación de casos de uso del sistema de préstamo de libros de una biblioteca. Vamos a recordar la definición breve de uno de los casos de uso que fueron identificados como de mayor riesgo, es decir, que es esencial para el sistema, como el de Registrar préstamo. En dicha definición vamos a subrayar algunas palabras que pueden referirnos, de acuerdo con la categorización propuesta, a clases conceptuales.

Caso de uso Registrar préstamo Actor (es) Bibliotecario Descripción: el bibliotecario pide al usuario la identificación de éste y consulta el estado de morosidad de la persona. Si está a derecho, lee los datos de un material bibliográfico que será prestado. Los datos se leen a través de una etiqueta de código de barra que viene en el material. El sistema, con respecto a las restricciones y la frecuencia de uso del material, sugiere el tiempo de préstamo conveniente de acuerdo con la demanda. El bibliotecario registra finalmente los datos del material prestado.

68

Observe cómo, en primer lugar, aparecen roles de personas en el sistema: bibliotecario y usuario. De igual forma podemos notar cosas como material bibliográfico que es lo que se registra en una transacción (que como tales, las transacciones constituyen conceptos) como es el préstamo. Otras transacciones como la morosidad (las cuales son consultadas), que pudieron ser registradas en otro momento, intervienen en los conceptos que estamos identificando para el proceso.

Tipos de clases conceptuales Clases identificadas Roles Usuario, Bibliotecario Cosas Material bibliográfico Transacciones Préstamo, Morosidad

Recordemos que el UP plantea identificar los casos de uso clave del sistema (también vistos como los de mayor riesgo) para desarrollarlos con especial atención. Y, por otra parte, tales casos de uso deben servir como guía para desarrollar una arquitectura que pueda sustentar de forma sólida al sistema. En este punto podemos comenzar a crear un modelo conceptual de nuestro sistema de préstamo de la biblioteca. En primer lugar, podemos enumerar varios conceptos encontrados: ƒ

Usuario

ƒ

Préstamo

ƒ

Bibliotecario

ƒ

Material bibliográfico

ƒ

Morosidad

Fíjese que esta lista es parecida a la que encontramos analizando la descripción breve de casos de uso. Un ingeniero de software con experiencia, podrá deducir desde el momento que escribe los casos de uso, conclusiones y elementos importantes referidos al modelo de clases. Es posible que utilizando la descripción detallada de casos de uso podamos encontrar nuevos conceptos no considerados en la descripción breve. Eso vamos a revisarlo más adelante. Con los conceptos hallados, podemos trazar un primer modelo conceptual. En este solamente incluiremos los conceptos como tales, sin detallar atributos u

69

operaciones, lo que podríamos decir que es el “cascarón” de las clases que queremos desarrollar. Condiciones Préstamo

Bibliotecario

Préstamo

Material

Usuario

Registro Morosos

Figura 10. Conceptos del Sistema de Préstamo Bibliotecario.

Analicemos por un momento el modelo que hemos construido. ¿Qué conceptos hemos encontrado? Y a partir de éstos, ¿qué nuevas preguntas se nos presentan? Observemos que hay algunos conceptos que podemos representar muy naturalmente a partir de la descripción que hemos desarrollado en el caso de uso. Por ejemplo, las personas involucradas como el Bibliotecario y el Usuario, la transacción de Préstamo y el Material que presta la biblioteca. Hay otros conceptos que se desprenden de la descripción del caso de uso, por ejemplo, un Registro de Morosos que se consulta cuando se está en el proceso del préstamo. Por otra parte, puede intuirse que debe haber algo en el sistema que pueda definir la Condición de préstamo para el material bibliográfico, donde se indique que un material sujeto de préstamo, tiene condiciones para ello: por ejemplo, que dicho material se presta solamente para uso en las instalaciones de la biblioteca, o bien para llevarlo fuera de ésta, así como el tiempo que puede prestarse, entre otros. Encontrar un concepto como éste quizás no sea tan inmediato, pero de alguna forma surge de la descripción misma del caso de uso. Cuando se indica que “el sistema, de acuerdo a las restricciones y la frecuencia de uso del material”, estamos frente a la necesidad de incorporar algún elemento que maneje las restricciones de préstamo que ahí se han descrito.

70

Finalmente, note cuán importante es la descripción de un caso de uso para poder ir definiendo los conceptos que requerimos para poder elaborar nuestros modelos de clases. Por ello acá reforzamos la importancia que les otorga el Proceso Unificado (UP): una buena comprensión y definición de los casos de uso conlleva a que todo pueda depender de ellos para los elementos que deben crearse para la solución requerida. El hecho que se diga que el UP está guiado por casos de uso, no es casual. DIFERENCIAR CONCEPTOS QUE SON CLASES Y CONCEPTOS QUE SON ATRIBUTOS En este punto lograríamos apelar a la intuición para definir conceptos que podrían ser clases. Sin embargo, un consejo que nos da Larman (2003) es una regla empírica (como tantas que usamos en la informática), previniéndonos de errores típicos en la definición de las clases conceptuales. Tal error se manifiesta muchas veces en incluir en una clase un atributo, cuando realmente es una clase. La “regla de oro” que nos da este autor es la siguiente: si no consideramos

alguna clase conceptual X que sea un número o texto en el mundo real, X es probablemente una clase conceptual, no un atributo.

¿Qué nos quiere decir Larman con ello? Que generalmente, cuando estemos planteando un modelo conceptual, si nos topamos con algún concepto que puede expresarse con tipos de datos primitivos, es decir, números, cadenas de texto, caracteres, boléanos, o cualquier otro que pueda proveer un lenguaje de programación, entonces estos serán potencialmente atributos. Si nos tropezamos con un concepto que se expresa como algo más complejo que números, texto o cualquier tipo primitivo, entonces ese concepto deberá ser una clase. Un ejemplo que el autor nos ofrece es el siguiente.

Vuelo

Vuelo

Aeropuerto - nombre : String - ciudad : String

- destino :

Figura 11. Diferencia entre clases conceptuales y atributos.

71

A la izquierda de la Figura 11 vemos una clase conceptual llamada Vuelo que tiene un atributo llamado destino. ¿Qué es destino en este caso? Es un aeropuerto donde debe llegar ese vuelo. En ese caso, destino se vuelve mucho más complejo que ser solamente un atributo definido, por ejemplo, por un tipo de datos primitivo, digamos que una cadena de texto (String). Una mejor definición conceptual se da a la derecha de la Figura 11 donde tenemos la clase Vuelo por una parte y una clase Aeropuerto por otra parte. Note que aeropuerto posee dos atributos, nombre y ciudad, los cuales son parte de la caracterización que damos a esa clase. ¿Podríamos analizar cada una de las clases conceptuales halladas para el caso de la Biblioteca bajo esta óptica, es decir, que podamos indagar si ellas son mucho más complejas que un tipo de datos primitivo? Y es que si vemos la descripción del caso de uso que analizamos, nos topamos con un posible concepto cuando se menciona la “identificación del usuario” que introduce el bibliotecario. En ese caso podemos intuir que tal identificación podría ser tan simple como una cadena de caracteres, por lo cual pasaría ser un atributo de una clase, más que una clase en sí. En la siguiente tabla indagamos, tomando en cuenta la “regla de Larman”, las clases que hemos identificado en la Figura 11.

Nombre de la clase Bibliotecario Usuario Material Préstamo Registro Morosos Condiciones Préstamo

Atributos potenciales Identificación, Nombre Identificación, Nombre, Estado (activo, moroso, inactivo) Código, Tipo material Código, Fecha Préstamo, Tiempo préstamo, Fecha Devolución, Estado (abierto, devuelto, moroso) Fecha registro, Importe por morosidad, Estado (abierto, cancelado) Tipo de préstamo (Interno en la Biblioteca, A domicilio), Tiempo de préstamo.

Tabla Nº 3. Representación de clases de la Figura 11, usando la “regla de oro” sugerida por Larman.

Observe, entonces, que al evaluar algunos atributos potenciales que hay en los conceptos que identificamos, nos damos cuenta que el concepto debe expresarse a través de un conjunto de atributos, por lo cual podemos intuir que estamos, potencialmente ante clases conceptuales.

72

Al revisar la lista de atributos usted podrá preguntarse en este momento (y con sobrada justificación): ¿pero para registrar un préstamo debo saber qué estoy prestando (material) y a quién se lo estoy prestando (usuario)? Para responder a lo anterior, fíjese que en un primer momento vamos a encontrar conceptos como los que hemos hallado en este sistema: préstamo, material, usuario, etc. Sabemos que estos conceptos, expresados luego como clases conceptuales deberán relacionarse entre sí. Producto de esas relaciones es que cada una de estas clases, dentro de sus atributos, podrá incorporar objetos de las clases que necesitan, como es el caso de Préstamo con respecto a Material y a Usuario. Cuando elaboramos el modelo conceptual, en un primer momento tenemos que esforzarnos por descubrir los atributos propios de la clase que estamos tratando de definir. Mientras tanto, los atributos, que son objetos de otras clases, tal como mencionamos, se expresarán producto de la definición de las relaciones entre esas clases. Finalmente, note que, mientras realizábamos la comprobación de que si nuestros conceptos son clases o atributos, descubrimos, valga la redundancia, algunos atributos importantes que deben tener nuestras clases.

RELACIONES1 CONCEPTUALES ENTRE CLASES Estudiemos con más detalle el tema de las relaciones entre clases. En un modelo conceptual debemos encontrar relaciones importantes que deben darse entre las clases, de forma tal que pueda visualizarse qué tipo de “colaboración” debe darse entre ellas. Al mencionar la palabra colaboración, debemos recordar que cada uno de los elementos que estamos identificando, esto es, las clases conceptuales, son parte de un todo que es el sistema. Por lo tanto, no hay elementos aislados, sino que ellos conforman parte de una arquitectura. Tal como lo mencionamos anteriormente en este libro, la arquitectura debe verse como un sistema y, tal como en una casa, cada una de las habitaciones, ventanas, tomas de corriente, tuberías, etcétera, colabora para varios objetivos que tienen sus residentes: “Dormir”, “Iluminar habitación”, “Ventilar casa”, etc. Así entonces, para cumplir 1

En este caso se va a usar el término relación cuando se trate del modelo conceptual. Otros autores también utilizan el nombre de asociación, como el caso de Larman. Sin embargo cuando se estudie el modelo de diseño, se va a analizar un tipo específico de relación cual es la asociación, por lo cual, para no confundir términos, como mencioné anteriormente, se utilizará el término de relación en esta etapa.

73

los objetivos del Sistema de Préstamo Bibliotecario, debemos encontrar cómo se relacionan las clases unas con otras, en términos de poder definir la colaboración que vamos a necesitar. En el apartado anterior ya habíamos mencionado brevemente algunas colaboraciones que se necesitan para poder registrar un préstamo. Esta transacción requiere establecer aspectos como: fecha en que se presta, cuánto tiempo se presta, estado del préstamo, entre otros. Además, debe saber a cuál usuario de la biblioteca se le presta y cuál material se le está prestando. Al encontrarnos con esta necesidad de colaboración de registrar un préstamo, podemos ir modificando nuestro modelo conceptual tal como se establece en la Figura 12:

Condiciones Préstamo

Bibliotecario

Préstamo

Material

Usuario

Registro Morosos

Figura 12. Definición de primeras relaciones entre clases conceptuales para el Sistema de Préstamo Bibliotecario.

En la figura anterior podemos notar ya el hecho de que, para poder registrar un préstamo, debemos contar con la colaboración de las clases de Material y de Usuario.

Cardinalidad de las relaciones Al establecer relaciones entre clases, debemos poder definir también lo que se denomina la cardinalidad de la relación. Entendemos por cardinalidad el número de ocurrencias que pueden existir en la relación entre las clases. Por ejemplo,

74

para la relación entre material y préstamo pueden definirse las siguientes políticas. En todo préstamo no hay límite, en cuanto a número de los materiales que el usuario desea pedir. Sin embargo, todo préstamo debe contar, al menos, con un material. En el diagrama esto se ve así: Material

1..*

Préstamo

En el extremo izquierdo de la relación se nota un 1..*, lo cual define que, partiendo de la clase Préstamo hacia la clase Material, debe haber, al menos, un material como límite inferior, aunque no hay límite superior en este caso, representado por el asterisco. Otra política de la Biblioteca podría ser limitar el número de materiales que pueden prestarse a la vez, digamos, cinco materiales por préstamo. De igual forma se establece que, para que se de un préstamo, al menos debe existir un material. El diagrama anterior se modificaría de la siguiente forma: Material

1..5

Préstamo

En este diagrama notamos, tanto el límite inferior, como el límite superior, para el número de ocurrencias de materiales que pueden facilitársele a un usuario en un préstamo. Por otro lado, podría quererse, por parte de la administración de la Biblioteca, que todo préstamo sea exactamente de un solo material. Así entonces, aunque el usuario acuda con “n” cantidad de materiales para que le sean prestados, el sistema registrará para cada uno de ellos, un préstamo distinto. En tal caso, la cardinalidad de la relación entre Préstamo y Material se vería así: Material

1..1

Préstamo

Note que cada préstamo puede contener uno, y solamente un material. La cardinalidad de Préstamo hacia Material que analizamos previamente, está sujeta a definiciones de la política de préstamo que tenga la Biblioteca. En ese sentido

75

puede ser “más libre” de definir, dado que puede ser cualquiera de las que hemos visto anteriormente como ejemplo. Quizás la única restricción que no puede obviarse es que, para que haya un préstamo, debe prestarse algo. Por lo tanto, el límite inferior de al menos un material por préstamo, es el que debe respetarse siempre, aunque puede haber variaciones en el límite superior. Lo importante, en todo caso, es que usted, como buen ingeniero o ingeniera de software, lleve a cabo las averiguaciones necesarias para una correcta definición. Como veremos más adelante, cualquier definición que se adopte, tendrá un impacto en el modelo que se construya. Ahora bien, la cardinalidad en la relación inversa a la analizada, de Material hacia Préstamo, debe pensarse también en los escenarios que son válidos de ocurrir. Pongamos el caso que vamos a pensar en el límite inferior de la relación: para que exista un material en el sistema, ¿debe necesariamente ocurrir un préstamo? La respuesta pareciera ser no. Por ejemplo, algún libro de Ingeniería de Software escrito por Roberto Cortés podría estar por años en una biblioteca y jamás ser solicitado para préstamo. Por otra parte, para pensar en el límite superior de la relación, un material ¿cuántas veces puede ser prestado?, ¿una vez?, ¿un número limitado de veces?, ¿todas las veces que se requiera? Analicemos estas situaciones: si sólo pudiera prestarse una vez, podría pensarse que la Biblioteca estaría adquiriendo materiales muy extraños que parecieran que no pueden prestarse más de una vez, por algún motivo desconocido. Tal no es el caso. Ahora bien, si fuera un número limitado de veces (pongamos, 5, 10 o cualquier otro número), sería una extensión de lo mismo que analizamos en el párrafo precedente para el caso de prestarse una sola vez, solo que definido a partir de un número mayor que uno. Entonces, pareciera que el material puede ser prestado una y otra vez mientras sirva. En este caso, el límite superior sería ilimitado, por lo cual se representa por un asterisco. Finalmente, la relación entre Préstamo y Material se vería de alguna de las siguientes formas: Material

1..1

0..*

1..5

0..*

Préstamo

O bien: Material

Préstamo

76

O bien: Material

1..*

0..*

Préstamo

Cada una de ellas, expresada de acuerdo con las políticas de ejemplo vistas para la definición de la cardinalidad hecha de Préstamo hacia Material. En la relación que une las clases de Préstamo y Usuario, también podemos hacer el mismo ejercicio. Piense usted: ¿cuántos préstamos puede hacer un usuario en el sistema? Y, por otra parte, ¿hacia cuántos usuarios está asociado un préstamo? Respóndase estas preguntas. Yo le propongo la siguiente respuesta y usted verificará el porqué de esta. Préstamo

0..*

1..1

Usuario

Nombre de las relaciones Otra buena práctica que se recomienda, es poder dar nombre a las relaciones. Nombrar una relación adecuadamente sirve para documentar de mejor forma el modelo que estamos creando. Así, al visualizar el modelo, se estaría facilitando una mejor lectura de éste. Pero, ¿cómo nombrar relaciones? No hay una receta definida, más que indicar algo significativo que describa la relación. Procuraremos, eso sí, expresar en una sola palabra tal relación y, también, nos esforzaremos para que la denominación de la relación sea hecha con base en la clase que necesita de la otra. ¿Qué se quiere decir con ello? Por ejemplo, en la relación Préstamo/Material necesitamos preguntarnos qué clase necesita de la otra para que tenga sentido. Ya vimos que Material tiene sentido sin que necesariamente haya un préstamo. No obstante, Préstamo requiere necesariamente de que haya, al menos, un material que se preste. Por lo tanto, uno podrá denominar la relación en términos de la necesidad de Préstamo hacia Material2. Un nombre candidato de esta relación 2

Note también que la cardinalidad de la relación puede ayudar definir ese rol de quién necesita a quién. En este caso se ha visto que Material, en su límite inferior de la relación con Préstamo, indica 0 (cero), esto es, que no necesariamente debe existir un Préstamo para que un objeto de la clase Material exista. Mientras tanto, el límite inferior de la relación de Préstamo hacia Material, el cual es uno, indica que debe existir dentro de Préstamo, al menos un objeto de la clase Material para que un objeto de la clase Préstamo pueda existir.

77

podría ser Incluye, SePrestan u otras denominaciones que expresen tal relación. En el diagrama veríamos algo parecido a lo siguiente.

Material

1..* Incluye

0..*

Préstamo

Note que el nombre de la relación se muestra al lado izquierdo de esta, leyéndose así: La clase Préstamo incluye los materiales que se prestan en la transacción de registro de préstamo de materiales en el sistema. Siguiendo con el mismo ejercicio, podemos establecer el nombre de la relación entre Préstamo y Usuario. Nuevamente, nos preguntamos quién necesita a quién, en esta relación. En este caso diremos que Préstamo requiere saber necesariamente a cuál usuario se le está prestando el material. Por el contrario, un objeto de la clase Usuario puede existir sin estar asociado nunca en su vida a un préstamo. Así entonces, podemos denominar la relación entre las clases Préstamo y Usuario en el contexto significativo de esta relación dentro del sistema, por ejemplo, con el vocablo adjudica. Así, para poder describir en nuestro modelo que el préstamo es adjudicado a un usuario, al trazar el diagrama lo veríamos de la siguiente forma:

Préstamo

Usuario 0..*

1..1 Adjudica

Ahora nos interesa ir completando el modelo conceptual del Sistema de Préstamo Bibliotecario. Al visualizar el modelo de clases conceptuales para el Sistema de Préstamo Bibliotecario que hemos definido hasta el momento, nos encontramos con el siguiente diagrama.

78

Condiciones Préstamo

Material

1..* Incluye

Bibliotecario

0..*

Préstamo

Usuario 0..*

1..1 Adjudica

Registro Morosos

Figura13. Modelo de clases conceptuales para el Sistema de Préstamo Bibliotecario.

Este modelo deberá irse completando. Para ello deben establecerse otras relaciones, que se propondrán a continuación, con el objeto de que usted las analice, de acuerdo con lo que hemos visto hasta ahora, y que sintetizamos en los siguientes pasos. a) Busque conceptos claves en los casos de uso. b) Analice si esos conceptos son atributos o clases conceptuales. c) Establezca, mediante relaciones, la colaboración que se requiere entre clases, para cumplir los objetivos del sistema. d) Defina la cardinalidad de la relación, de acuerdo con el análisis de políticas o reglas que se descubran en el contexto del sistema que se está diseñando. e) Nombre las relaciones con alguna palabra significativa, expresando la acción que se da entre las clases conceptuales. Un primer modelo conceptual completo lo podemos apreciar en el diagrama que observamos en el siguiente diagrama.

79

Condiciones Préstamo

Bibliotecario

1..1

1..1 HechoPor

1..1 RestringePrestamo Material

1..* Incluye

0..* 0..*

Préstamo

Usuario 0..*

1..1 Adjudica

1..1 GeneradoPor 0..* Registro Morosos

Figura 14. Modelo conceptual completo para el Sistema de Préstamo Bibliotecario.

Analicemos rápidamente el proceso para llegar a esta versión del modelo. En primera instancia, el caso de uso Registrar Préstamo, como uno de los casos de uso fundamentales del sistema, nos proporcionó varios de los conceptos y colaboraciones que ahí se muestran. De esta forma, apreciamos una clase conceptual central que es Préstamo, la cual requiere colaborar con la clase Material y la clase Usuario, para poder registrar la transacción que representa el préstamo de un material bibliográfico, para un usuario de la biblioteca. Tal transacción es realizada en el sistema por un Bibliotecario, tal como se muestra en la relación Préstamo/Bibliotecario. El bibliotecario puede registrar muchos préstamos e, incluso, podría no registrar ninguno. Un préstamo puede ser registrado por uno, y solamente un bibliotecario. Por otra parte, cada material define sus restricciones de préstamo mediante la clase Condiciones Préstamo. En este caso podemos suponer dos escenarios. Existen políticas generales de préstamo, por ejemplo, el material que permite prestarse para utilizar fuera de la biblioteca, puede ser otorgado en préstamo por 15 días. Por otra parte, el material que solamente puede utilizarse dentro de la biblioteca, es prestado por 5 horas.

80

Cada material tiene una política de restricción variable derivada de varios factores como: población usuaria potencial, cantidad de copias existentes en la biblioteca, tipo de material, demanda efectiva registrada del material, entre muchos otros. En tal caso, el sistema define una restricción específica para cada material en préstamo. De acuerdo con el diagrama, el escenario escogido es el segundo. Intente explicar por qué es este y no el primero. Por último, la relación Préstamo/RegistroMorosos puede derivarse del análisis de otro caso de uso. El caso de uso en cuestión es el llamado Registrar devolución con morosidad Caso de uso

Registrar devolución con morosidad

Actor (es) Bibliotecario Descripción: al procesar una devolución, luego de leerse los datos del material prestado, si se detecta que el material está sujeto a morosidad, se habilita un proceso para tramitar la multa que el usuario debe pagar. El sistema calcula dicha multa y el bibliotecario termina de registrar los datos de la devolución y de la multa para el usuario.

Observe que tenemos, en primera instancia, las acciones que registran la devolución, la cual podemos suponer es el cambio de estado del préstamo (por ejemplo, de un estado “abierto” a un estado “cerrado”). Al mismo tiempo tenemos que, durante ese proceso de devolución, se ha detectado una situación donde se genera la multa que debe pagar el usuario, por incurrir en atraso. De ahí que la colaboración existente entre estas dos clases puede expresarse como:

un registro de morosidad se genera a partir del registro de una devolución de un material prestado. En este caso, note que la clase de RegistroMorosos requiere de Préstamo, por eso el nombre de la relación se coloca en el extremo de la clase Préstamo.

Finalmente, la cardinalidad de esta relación se fundamenta en la siguiente argumentación: si la política de préstamo de la Biblioteca permite registrar por cada transacción un número ilimitado de material bibliográfico para un usuario, entonces, de igual forma podrían generarse, por cada préstamo, la misma cantidad de registros de morosidad. Por ejemplo, si se prestaron 8 distintos materiales para un usuario en un mismo préstamo, potencialmente podrían registrarse hasta 8 ocurrencias de morosidad. Podrían ser menos, por ejemplo, que el usuario devuelva a tiempo 3 materiales y 5 no los regrese aún. E igual podría no haber ningún registro de morosidad, por lo cual sabemos, entonces, que los objetos de la clase Préstamo pueden existir sin que haya registro de

81

morosidad. Entonces, la cardinalidad de Préstamo hacia RegistroMorosos es de 0 a muchos (visto en el diagrama de la Figura 14 como 0..*). Note que, por lo analizado, pueden generarse distintos registros de morosidad, en distintos momentos, para un mismo préstamo. Por ejemplo, un usuario podría devolver, en un momento dado, un material con atraso y luego, en otro momento, otro material que se otorgó a partir del mismo préstamo. Esta situación nos genera otro problema en el modelo: ¿cómo manejar estas devoluciones parciales? Dada esta situación, debemos manejar, de una forma particularizada, cada material prestado, es decir, no podemos suponer que todo se va a tratar al estilo de un “paquete”. Si bien todos los materiales solicitados por un usuario se prestan en un solo momento, la devolución no necesariamente será así. Vamos a retomar esta situación más adelante. Por otra parte, dado que un objeto de la clase RegistroMorosos se genera a partir de un objeto específico de la clase Préstamo este debe estar asociado a uno, y solamente uno, de los objetos de esta clase. En este punto tenemos un modelo conceptual de clases bastante adelantado en cuanto a las clases que podemos incluir potencialmente para nuestro sistema. Antes de avanzar a otras fases, como por ejemplo a la definición de atributos y operaciones en cada una de las clases (acercándonos a obtener clases de diseño), tenemos que tratar previamente aspectos que tienen que ver con la definición del modelo conceptual: las múltiples relaciones entre clases, clases relacionadas con ellas mismas y clases que sirven para especificar o describir una clase.

Relaciones múltiples entre clases Es posible que encontremos dentro del contexto de un problema, que una clase defina más de una relación con otra. Un ejemplo de ello podría ser la relación entre una clase Vuelo con una clase Aeropuerto (que vimos en otro ejemplo anteriormente). Sabemos que un vuelo tiene, al menos, una procedencia y posee, al menos, un destino. Tanto las procedencias, como los destinos son, en sí, aeropuertos. Seguidamente podemos ver cómo se refleja esa situación. 0..* Vuelo 0..*

1..* VuelaDesde 1..* VuelaHacia

Aeropuerto - nombre : String - ciudad : String

82

Note que la relación en la parte superior define las procedencias de un vuelo, mientras que la de abajo define los destinos. En algún momento observaremos cómo estas relaciones se transforman en atributos en las clases, por lo cual resulta importante definirlas.

Relaciones hacia la misma clase También es posible que podamos encontrar que una clase deba relacionarse consigo misma. Un ejemplo claro de esta situación, es lo concerniente a las materias que se imparten en una universidad y que forman parte de un plan de estudios. En este caso, vamos a encontrar que hay materias que son requisitos de otras. Dada esta situación, debemos relacionar la clase Materia con ella misma, tal como se muestra en el siguiente diagrama:

0..*

0..* Requiere

Materia

Así observamos que al definir esa relación, una materia puede requerir (o no requerir) de otras materias en el seguimiento de un plan de estudios.

Especificación de conceptos en el modelo de clases Otra situación que podemos encontrarnos en el planteamiento de una solución, es la necesidad de especificar un concepto de una forma más adecuada al funcionamiento que requerimos. Por ejemplo, en el caso de nuestro sistema de préstamo bibliotecario, tenemos la clase Material. Piense por un instante ¿qué queremos hacer nosotros con un objeto de esta clase en el contexto de nuestro sistema? Sí, ¡muy bien!… Queremos prestarlo (y recuperarlo, obviamente). Ahora bien, en realidad ¿qué prestamos? ¿El material en sí mismo o una copia del material? Y dado el caso que manejáramos copias (en el concepto legal de copias, no de fotocopias), ¿qué debemos controlar, además? Debemos controlar

83

la cantidad de copias del material existentes en la Biblioteca y, dentro de estas, verificar cuántas están prestadas. Revisemos una parte del modelo conceptual que tenemos planteado hasta el momento y analicémoslo a la luz de estas preguntas. Veamos la situación que se expresa en esta relación:

Material

0..*

1..* Incluye

Préstamo

Tal como la estudiamos anteriormente, el préstamo puede incluir muchos materiales para poder ser prestados en una sola transacción de Registrar Préstamo. Pero tal como nos cuestionábamos anteriormente, ¿se está prestando el material en sí mismo, visto como concepto, o bien, una copia de este? Tratemos de clarificar un poco más. Cuando estamos tratando el concepto de material, nos estamos refiriendo a la información general de un material bibliográfico. Tal información es un conjunto de atributos que definen, por ejemplo, si el material fuera un libro, especificar al autor, el nombre de la obra, quién la pública, el año, la edición, el ISBN, entre otros. Por lo tanto, la biblioteca cuenta con la información de cada una de los materiales que tiene a disposición de los usuarios. Sin embargo, si se relacionara directamente la clase Material con la clase Préstamo y, por ejemplo, la biblioteca adquiere 8 copias del mismo material, entonces habría que ingresar ocho objetos de la clase material, repitiendo la misma información de autor, nombre de la obra, ISBN, etc., cada vez. Esto no resulta práctico. Además, si por algún motivo la biblioteca perdiera todas las copias del material, esto implicaría que toda la información relativa a un material también desaparecería. Esto resulta en una situación sumamente impráctica, que debe resolverse mediante la utilización de otra clase que se denomina, según Larman (2003) como la especificación o descripción de una clase. En nuestro caso, pareciera conveniente contar con una clase relacionada con material, llamada Copia, que pueda ayudar al manejo de los préstamos del material en la biblioteca. Veamos cómo podría modificarse esta situación en nuestro diagrama.

84

Copia

Material - signatura : - copias :

1..1 Concretiza

0..*

- id_copia : - estado_copia :

En este caso, vemos cómo una copia del material concretiza la existencia del material en la biblioteca. Una copia está asociada a uno y solo un material, mientras que el material puede tener ya sea ninguna, o muchas copias de este. Vemos algunos atributos significativos (los cuales, ya pronto, iremos completando en el siguiente apartado). Por ejemplo, dentro de una Biblioteca es sumamente importante la identificación de un material, en términos de sus necesidades. Tal identificación se hace mediante una signatura. Además, la clase Material puede mantener, a través del atributo copias, la cantidad de copias que hay actualmente en la biblioteca. Esta podría disminuir o aumentar, de acuerdo a pérdidas o adquisiciones que se hagan para dicho material. Muy relacionado con ella tenemos la clase Copia. Vea que tal es el ligamen que se indica que Copia concretiza la clase Material en el contexto de la biblioteca. Vea que tan es así, que usted mismo puede ir a consultar un material en cualquier biblioteca (a través de un sistema computarizado de búsqueda, o bien, no hace mucho tiempo, en los gabinetes con tarjetas) y lo que tiene usted allí es una referencia del material y dónde puede ubicarla. Con esa información usted va a los estantes y toma una copia del material, es decir, algo que concretiza lo que usted halló en el sistema o en el tarjetero. La clase Copia tiene algunos atributos importantes: la identificación de la copia, dado que, si bien todas ellas se refieren al mismo material, una copia es distinta de la otra. Además, tenemos un estado de la copia, que podemos suponer, por ahora, que se trata de algo que puede indicarnos algo con respecto de ella: si está disponible, si está prestada, si está perdida, si está en reparación o si está anulada de las existencias. Con respecto a Préstamo, lo que va a prestarse, por lo tanto, no es un objeto de la clase Material, sino una copia ligada a ella. El diagrama resultante se vería así:

Copia

Material - signatura : : - copias

1..1 Concretiza

0..*

: - id_copia - estado_copia :

85

Préstamo 1..* Incluye

0..*

Note que a partir de este cambio, lo que expresa el diagrama es que lo que se incluye en el préstamo son una o varias copias de distintos materiales (al menos una), y por otra parte, la copia de un material puede estar en ninguno o en varios préstamos distintos. Párrafos atrás identificamos un problema con respecto a la dinámica del préstamo. En ese momento analizábamos que, dada la política de poder prestar varios materiales (o, dada la modificación, copias de materiales) en una sola transacción de préstamo, la devolución podía tener un comportamiento variable: un usuario podía devolver las copias en distintos momentos. Dado lo anterior, parece imposible manejar en la clase Préstamo un solo estado para que maneje la situación individual de la devolución de cada una de las copias prestadas. Por eso, el atributo estado_copia en la clase Copia, va a poder determinar el estado individual de una copia de un material, en algún momento del tiempo. A su vez, las copias relacionadas en un préstamo van a permitir definir un estado general de dicho préstamo. Esto por cuanto un atributo de estado en Préstamo, podría indicar el estado general de este: por ejemplo, puede indicar si un préstamo particular está abierto (tiene devoluciones pendientes) o cerrado (ya no tiene devoluciones pendientes). Por último, en RegistroMorosos es importante ubicar cuál copia de material, en particular, es la que está generando que se de la morosidad. Por lo tanto, es importante poder relacionar este registro con la clase Copia. Todo este análisis nos lleva, por lo tanto, a poder modificar el diagrama de esta forma:

Copia

Préstamo

: - id_copia - estado_copia :

1..* Incluye

0..*

1..1 GeneradoPor

1..1 SeFundamentaEn

0..* 0..* Registro Morosos

86

Vemos que se agrega una relación entre RegistroMorosos y Copia, donde se indica que una morosidad se genera por la acción de devolución en Préstamo, pero que debe fundamentarse en identificar cuál copia de un material está generando tal registro. Ahora bien, la lectura de los casos de uso también nos pudo haber ayudado a identificar la clase Copia, como algo asociado a la clase Material y dentro del funcionamiento deseado. Cuando estudiamos la descripción detallada del caso de uso Registrar Préstamo, notamos en uno de sus pasos la aparición del concepto que acá hemos analizado. En letra cursiva y negrita de la siguiente tabla, encontrará lo relacionado en el caso de uso con el concepto de Copia . Caso de uso Registrar préstamo Objetivo Registrar la información de préstamos de un material bibliográfico que se le hace a un usuario de la biblioteca de la Universidad. Actores Bibliotecario Condiciones El Bibliotecario deberá tener en sus manos el material por prestar, ya sea que el previas usuario se lo haya proporcionado, o bien que él mismo haya tenido que buscarlo, dado que es de préstamo restringido. Además de contar con la identificación del usuario que lo habilite para poder usar el servicio de biblioteca. Escenario El caso de uso comienza cuando el Bibliotecario ingresa al sistema la identificación del usuario. El Sistema le indica si el Usuario es válido. El Sistema, además le indica si el Usuario tiene algún registro de morosidad. Una vez comprobados los pasos anteriores, el Bibliotecario lee del Sistema Bibliotecario la información del material que se va a prestar, a través de un lector de código de barras. En ningún caso puede prestarse otra copia del mismo material al mismo usuario, lo cual se comprueba, por parte del Sistema, cuando se hace esta lectura. El Sistema indica si el material puede ser prestado solo para uso interno de la biblioteca y el tiempo que puede ser prestado en cualquier caso. El Bibliotecario registra el préstamo del material y el caso de uso termina. Excepciones En el paso 1, de comprobarse que el usuario no está registrado en la biblioteca, o cursos el caso de uso termina. alternativos En el paso 2, si el usuario está moroso, el caso de uso termina. En el paso 3, si el código de barras del libro esté ilegible, el Bibliotecario deberá ingresar este directamente en un campo de edición de la pantalla. En el paso 3, de comprobarse que el usuario ya tiene una copia del mismo material asignado en otro préstamo, el caso de uso termina. En el paso 4, luego de indicarle al usuario las restricciones del préstamo, éste puede decidir no aceptar las condiciones, por lo cual el Bibliotecario termina la ejecución del caso de uso. Condiciones De cumplirse el paso 5, el sistema guarda el registro del préstamo efectuado al posteriores usuario. El material debe quedar en estado de “prestado”.

87

Una vez más (y se insiste con ello para hacerle ver su trascendencia) vea la importancia de los casos de uso. Si usted estudia la descripción detallada de este caso de uso, deberá darse cuenta cómo se justifica aún más el modelo conceptual: recuerde, la arquitectura del sistema es quien tiene que sostener cada uno de los casos de uso, y con mucho más razón, los que son críticos para el sistema. Finalmente vea las implicaciones que conlleva analizar bien el contexto de la especificación de una clase. Note que un concepto, como Material no basta por sí mismo para poder manejar totalmente la funcionalidad que estamos buscando obtener en la colaboración que deben expresar las clases. Por lo tanto, debemos añadir una clase de especificación, en este caso la clase Copia. En otros contextos, igualmente, podemos encontrar ejemplos en los que debemos manejar una especificación para un concepto. Imagine dentro de una fábrica el concepto Producto. En este concepto podríamos tener los detalles del nombre, de la descripción del producto, entre otros. Cuando se hace la manufactura de un producto, podríamos tener la información específica asociada: número de serie, cantidad fabricada, etcétera. Esta clase específica podría llamarse Producción. En este caso encontramos que la clase Producción describe, precisamente, lo que es la producción de un producto. Producción

Producto : - nombre - descripción :

0..*

1..1 Describe

- número_serie : : - cantidad

En el contexto de una universidad, con el caso de las materias que componen un plan de estudios, una especificación de la clase puede darse en el momento en que se hace la matrícula. En este caso, un estudiante no matrícula una materia: una materia, en sí, es una descripción general de contenidos, objetivos, número de créditos y otros aspectos relativos a los propósitos académicos que se persiguen. Lo que matricula un estudiante es un Curso, el cual está asociado a un periodo lectivo, a un profesor, a un aula, a un grupo. Curso es una clase de especificación de una clase Materia. Volviendo a nuestra biblioteca, nuestro diagrama conceptual tiene una fisonomía bastante avanzada desde que empezamos a elaborarlo. Note ello en los siguientes diagramas:

88

Diagrama inicial Condiciones Préstamo

Bibliotecario

Préstamo

Material

Usuario

Registro Morosos

Diagrama actual

Condiciones Préstamo

Bibliotecario

1..1

1..1 HechoPor

1..1 RestringePréstamo

0..* Copia

Material - signatura : : - copias

1..1 Concretiza

0..*

Préstamo

- id_copia : - estado_copia :

1..* Incluye

1..1

Usuario 0..*

1..1 Adjudica

1..1 GeneradoPor

1..1 SeFundamentaEn

0..* 0..* Registro Morosos

Figura 15. Diferencias entre el diagrama del modelo conceptual inicial y el actual del Sistema de Préstamo Bibliotecario.

89

Preste atención a la sofisticación que se ha seguido desde que iniciamos con un simple listado de conceptos encontrados en los casos de uso. Posteriormente hemos añadido relaciones, la cardinalidad, el nombre de las relaciones y la especificación de clases conceptuales. Para poder llegar a este punto, y sobre todo para poder analizar el tema de la especificación, hemos tenido que iniciar, también, con la definición de atributos en las clases. En el siguiente apartado continuaremos con esta tarea. AÑADIENDO ATRIBUTOS AL MODELO CONCEPTUAL Tal como lo vimos al inicio del libro, cuando tratamos clases en el paradigma de orientación a objetos, dos temas son importantes de definir: los atributos que caracterizan a cada uno de los objetos y los métodos que describen el comportamiento que podemos obtener de dichos objetos. Por ahora vamos a detenernos en añadir atributos para cada una de las clases del modelo. En un momento nos toparemos con otras decisiones importantes que deberán impactar dicho modelo. Pero vamos a comenzar por lo más sencillo. Los atributos, tal como lo mencionamos, van a definir características en cuanto a datos que deben contener las clases conceptuales que hayamos identificado. En primera instancia, debemos tener en cuenta lo siguiente: se van a definir atributos en cada clase que sean simples, es decir, que puedan verse como tipos primitivos. Es muy posible que una clase vaya a tener atributos que no sean tipos primitivos, sino que sean complejos, posiblemente que deban contener atributos que son objetos de otras clases. Eso sucedería, por ejemplo, en la clase Préstamo, donde se requeriría saber qué objeto de la clase Usuario y cuál de la clase Copia están asociados con un préstamo particular. En esa perspectiva, podría proponerse una definición de atributos para la clase Préstamo así: Préstamo -

número_préstamo fecha_préstamo estado_préstamo material_prestado usuario_adjudicado

Veamos uno a uno los atributos.

90

: : : : :

número_préstamo: es el número de préstamo que se genera en la transacción y

que lo identifica de forma única en el sistema. fecha_préstamo: es la fecha en que se realiza el préstamo. material_prestado: es el conjunto de materiales prestados en el préstamo. usuario_adjudicado: es el usuario al cual se le asigna o adjudica el material prestado. Note que dentro de esos atributos hay algunos que podrían ser datos que son de tipo primitivo y otros que son complejos y son de otras clases. Como regla, para la definición de atributos de una clase, debemos encontrar e incluir aquellos que son sencillos, en general, que puedan representarse con tipos primitivos, como números enteros, caracteres, números reales, fechas, horas, cadena de caracteres, entre otros. Los atributos que son complejos y que obedecen a objetos de otras clases que se encuentren en el mismo modelo conceptual, los expresaremos mediante relaciones. Entonces, la clase Préstamo quedaría mejor expresada, en cuanto a atributos, de la siguiente forma: Préstamo Copia - id_copia - estado_copia

: :

1..* Incluye

1..1

- número_préstamo - fecha_préstamo - estado_préstamo

: : :

Usuario 0..*

1..1 Adjudica

Para ir completando el modelo, podemos retomar la Tabla Nº 3 que comenzamos a elaborar cuando analizábamos si un concepto respondía a ser un atributo, o bien a una clase conceptual. Dicha tabla presenta atributos potenciales en cada clase conceptual. Ahora podemos modificarla un poco, de acuerdo con la evolución del conocimiento que hemos tenido del sistema. Veamos cuál era la situación de la tabla en aquel momento. Nombre de la clase Bibliotecario Usuario Material Préstamo

Atributos potenciales Identificación, Nombre Identificación, Nombre, Estado (activo, moroso, inactivo) Código, Tipo material Código, Fecha Préstamo, Tiempo préstamo, Fecha Devolución, Estado (abierto, devuelto, moroso) Registro Morosos Fecha registro, Importe por morosidad, Estado (abierto, cancelado) Condiciones Préstamo Tipo de préstamo (Interno en la Biblioteca, A domicilio), Tiempo de préstamo. Tabla Nº 4. Atributos potenciales de las clases conceptuales del Sistema de Préstamo Bibliotecario.

91

Observe que algunas clases pueden mantenerse tal como las definimos en aquel momento, tal es el caso de Bibliotecario y Usuario. De igual forma, RegistroMorosos y CondicionesPréstamo parecieran tener los atributos necesarios para caracterizar los datos que pueden manejar. Quizás, para efectos de transacción, haría falta que RegistroMorosos incluyera la fecha en que se cancela el importe. Podría incluirse otro atributo que lograría indicar cuál fue el número de documento del pago realizado. El análisis de ello conseguiría abrir paso a la existencia de otra clase, llamada algo así como PagoMorosidad. Este caso lo retomaremos más adelante. En cuanto a Préstamo y Material, la aparición de la clase Copia debió modificar algunos aspectos de los atributos que se consideraron en primera instancia. En sí la clase Copia deberá tener sus propios atributos los cuales, ya hemos visto, son identificación de la copia y estado de la copia. La clase Préstamo incluirá los atributos que se han visto en la Tabla Nº 4 anterior, con algunas diferencias. El atributo código lo hemos visto como número o identificación del préstamo; la fecha de préstamo, que es cuando se registra el préstamo, el estado del préstamo que obedecerá a un estado general de todos los materiales que se prestaron (no a la situación particular de cada uno de éstos) y que se expresa en valores como: abierto y cerrado. Ahora bien, fecha de devolución podría no tener más significado en la clase, puesto que no puede individualizarse para cada una de las copias de los materiales que se prestaron. Cada copia de material debería tener su fecha de devolución. Ahora bien, ante esto tendríamos que ver dos opciones: o bien crear una clase Devolución que se ubica entre las clases Copia y Préstamo, la cual manejaría para cada copia de material prestado la fecha en que este se devuelve, o bien, podemos pensar que la fecha de devolución solo tiene sentido si se hace de forma tardía. Tal fecha se incluye, efectivamente, en la clase RegistroMorosos. Tal decisión debe obedecer a cuántos controles debe tener en sus transacciones el sistema. La buena práctica diría que debemos incluir esa nueva clase. No obstante, para efectos de no complicar más el modelo, vamos a escoger la segunda opción la cual, además, maneja el proceso más crítico de las devoluciones: la que genera registros de morosidad. Dado este primer análisis, tenemos algunas modificaciones importantes que hacer en la Tabla N° 4 de atributos. La nueva versión sería la siguiente.

92

Nombre de la clase Bibliotecario Usuario Material Copia Préstamo Registro Morosos Condiciones Préstamo

Atributos potenciales Identificación, Nombre Identificación, Nombre, Estado (activo, moroso, inactivo) Signatura, Tipo material, Copias existentes, Copias disponibles, Copias prestadas Identificación copia, Estado copia (disponible, prestada, en reparación, anulada) Código, Fecha Préstamo, Hora préstamo, Tiempo préstamo, Unidad de tiempo, Estado (abierto, cerrado) Fecha registro, Importe por morosidad, Estado (abierto, cancelado), Fecha de pago Tipo de préstamo (Interno en la Biblioteca, A domicilio), Tiempo de préstamo, Unidad de tiempo

Tabla N° 5. Actualización de los atributos de las clases conceptuales del Sistema de Préstamo Bibliotecario.

Note que se han incluido algunos otros atributos importantes: en Préstamo se tiene la hora de préstamo, la cual es importante de tener, dado que se puede estar ante préstamos que son por hora. Por lo tanto, es necesario también identificar la unidad de tiempo que se presta, es decir, si se presta por horas o por días. Este atributo de unidad de tiempo también se incluye en la clase CondicionesPréstamo. Se ha modificado en Material el nombre de código por el de signatura, lo cual es más correcto en el contexto de las bibliotecas. Esta clase también tendrá la responsabilidad de manejar las “existencias” de las copias del material que hay en la biblioteca. Por ello se añaden el número total de copias existentes, el número de copias disponibles (esto es, la cantidad de copias que pueden prestarse. No siempre todas las copias podrían ser sujetas de préstamo, por ejemplo si alguna está en reparación, o bien se adquieren para prestarse a estudiantes becados, u otra situación especial). También está el número de copias prestadas, cuya actualización reduce o incrementa el número de copias disponibles. Intencionalmente no vamos a profundizar en otros atributos obvios de un material como: autor, nombre, entre otros, para tocar, más adelante, un tema importante de nuestro modelo. Hasta este punto advierta que deducir atributos es, como todo lo que se elabora en el Proceso Unificado, algo iterativo. Conforme usted va escribiendo y analizando el sistema, van surgiendo cuestionamientos importantes. No obstante, reflexione en qué momento lo estamos haciendo: no se ha codificado nada,

93

solamente se ha modelado, y sin embargo todo ello tiene consecuencias importantes en la programación del sistema. Recuerde que el Proceso Unificado se fundamenta en iteraciones, y al cabo de éstas, los productos (que pueden ser estos modelos conceptuales) se validan conforme se hacen revisiones. Tales revisiones pueden direccionar a que se agreguen requerimientos que no se habían considerado y tengan implicaciones que, por ejemplo, lleven a que se modifiquen, se quiten o se añadan atributos, tal como lo estamos haciendo ahora. Así, pueden obtenerse versiones preliminares hasta consolidar una versión donde pueda observarse que muchos aspectos del modelo, en cada clase, se consolidan, de acuerdo a la funcionalidad y el control que se requieren. A partir del análisis representando en la Tabla N° 5 anterior, podemos modificar nuestro modelo nuevamente para tener una versión con los atributos que se han identificado.

94

-

Material

signatura copias_existentes copias_disponibles copias_prestadas

1..1 RestringePréstamo

1..1

- tipo_préstamo - tiempo_préstamo - unidad_tiempo

: : :

Condiciones Préstamo

: : : :

1..1 Concretiza

0..*

1..* Incluye

1..1 SeFundamentaEn

: :

1..1

0..*

-

: : :

fecha_registro importe_moroso estado fecha_pago

Registro Morosos

0..*

: : : :

1..1 GeneradoPor

- número_préstamo - fecha_préstamo - estado_préstamo

Préstamo

0..*

1..1 HechoPor

: :

0..* 1..1 Adjudica

95

Figura 16. Visualización de las clases conceptuales y sus atributos.

- id_copia - estado_copia

Copia

Bibliotecario - id_usuario - nombre

Usuario - id_usuario - nombre - estado

: : :

Del diagrama anterior se obtiene una visión bastante completa del modelo que incluye las clases conceptuales y sus atributos con una definición más avanzada. Quedan dos temas pendientes: uno es con respecto al pago de los cargos por mora por parte del usuario y el otro con respecto a la definición de la clase Materiales. Empecemos por la primera situación. Si bien no habíamos incluido un caso de uso de Pagar Préstamos Morosos por parte del usuario, a la luz de que estamos usando el Proceso Unificado y que pueden surgir requerimientos al respecto, vamos a reflexionar un momento acerca de ello. En primera instancia, podríamos suponer que se añade un caso de uso para el manejo de esta funcionalidad. Este podría definirse de la siguiente forma: Caso de uso Pagar Préstamo Morosos Actor (es) Cajero Descripción: el cajero recibe, por parte de un usuario de la biblioteca, el pago por concepto de cancelación de morosidad en el préstamo de material bibliográfico. De la lista de préstamos con morosidad, el cajero cancela los que cubran la cantidad de dinero dada por el usuario. Si el usuario no queda con pagos pendientes, entonces cambia el estado del usuario de moroso a activo. Se emite un documento de recibo de pago.

Este caso de uso incluye un nuevo concepto, el cual es, además, una nueva clase: Pago. El pago se asocia con un conjunto de registros de morosidad, los cuales, como ya se vio, fueron generados por devoluciones atrasadas de copias de material bibliográfico. Otro concepto añadido al sistema, es el de Cajero. El diagrama, visto parcialmente en las clases que atañen, podría modificarse de la siguiente forma: Usuario

Préstamo - número_préstamo : : - fecha_préstamo - estado_préstamo :

0..*

1..1 Adjudica

- id_usuario : : - nombre : - estado

1..1 PagadoPor

1..1 GeneradoPor

0..* Pago

0..* Registro Morosos -

fecha_registro importe_moroso estado fecha_pago

: : : :

1..1 1..* Cancela

-

id_pago número_recibo monto_pago fecha_pago

Cajero : : : :

0..*

1..1 Registra

- id_cajero : - nombre :

Figura 17. Incorporación del caso de uso de Pagar Préstamos Morosos al modelo conceptual de clases del Sistema de Préstamos Bibliotecarios.

96

Un objeto de la clase Pago se genera para cancelar, al menos, un registro de morosidad. El pago es pagado por un usuario (el cual puede tener asociado muchos pagos para un mismo préstamo o para distintos préstamos) y es registrado por un cajero. Otro aspecto del modelo que hay que considerar, es lo relativo a la clase Material. El material que puede ser prestado en la Biblioteca puede ser de distinta índole: un libro, una revista o un vídeo. Esto nos lleva a pensar que podemos aprovechar uno de los mecanismos provistos por el paradigma de orientación a objetos, el cual es la herencia. Por el momento nos detendremos a pensar cuáles atributos pueden ser generales para los tres materiales, y cuáles son particulares para cada uno de éstos. Ya hemos visto que la clase Material contiene los atributos relativos a la signatura y el control cuantitativo de las copias del material. Estos atributos serán comunes para todo tipo de material de la Biblioteca. Ahora bien, para especializar una jerarquía de herencia en cuanto a los materiales que se prestan en esta Biblioteca, debemos pensar qué atributos son específicos para cada uno de ellos. Hagamos el ejercicio para cada caso en la siguiente tabla.

Tipo de material Libro Revista Vídeo

Atributos Autor, Título, Temas, ISBN, Edición, Editor, Año, Número de páginas, Idioma, País Nombre, Año, Volumen, Editor, ISSN, Idioma, País, Especialidad, Temas Nombre, Compañía productora, Director, Año, Duración, Idioma, Temas

Tabla N° 6. Análisis de atributos por cada uno de los tipos de materiales bibliográficos.

Podemos con este listado de atributos darnos una pequeña idea de lo que podrían describir las características de cada uno de los materiales que se prestan en la Biblioteca. Note que podemos encontrar algunos atributos comunes para todos: idioma, año y temas (referidos a los temas o palabras claves de cada material, tal como sería el caso de Ingeniería de Software, Análisis y Diseño Orientado a Objetos, Proceso Unificado, para el caso de este libro). Algunos otros atributos, luego de analizarlos, podría decirse que tienen propósitos comunes, si bien pueden llamarse diferentemente. Tal es el caso de título y nombre, o de compañía productora y editor. Uno podría atreverse a ponerlos como atributos comunes para las clases, buscando un nombre adecuado o escogiendo alguno (por ejemplo nombre) y que tenga un significado en el contexto particular de una clase (por ejemplo documentar que el atributo nombre se refiere a título en el caso de la clase Libro). Sin embargo, tales

97

decisiones se dan cuando se definen las clases de diseño, más que en las clases conceptuales. Dado que estamos, precisamente, en la definición de clases conceptuales, dejaremos estas decisiones para después. La parte del diagrama que se modificará se detalla a continuación. Material

Tema - nombre_tema :

1..* DescritoPor

0..*

# # # # # # #

Revista

Libro -

autor título ISBN editor páginas

: : : : :

: : : : : : :

signatura copias_existentes copias_disponibles copias_prestadas año país idioma

-

nombre volumen editor ISSN especialidad

Video : : : : :

+ + + +

nombre productora director duración

: int : int : int : int

Figura 18. Modelo conceptual de la clase Material Bibliográfico, definida por mecanismos de herencia.

De los atributos vistos en la Tabla Nº 6, se ha decidido hacer una clase conceptual aparte llamada Tema. Vimos cómo un material particular puede ser descrito por palabras claves o temas. Estos temas pueden ser muchos, lo cual trasciende el hecho de que sea un atributo simple. De hecho, la biblioteca podría tener una lista predeterminada obtenida de un catálogo de temas (lo que en la disciplina de Ciencias de la Información se llama un tesauro). Acá no se desarrollará la estructuración del sistema bibliotecario en cuanto a su catálogo, sino que nos centraremos esencialmente en el préstamo y en la devolución de materiales. Sin embargo, es importante visualizar aspectos importantes de este, como la jerarquía por herencia que hemos descrito, por cuanto nos hace ver las grandes posibilidades que se tiene al diseñar bajo la óptica del ADOO. La relación Copia/Material se mantiene tal cual. Copia tendrá un objeto de tipo material (lo veremos más adelante). En ese caso, dicho material puede ser cualquiera: un libro, o un video, o una revista. ¡Para efectos del diseño conceptual, no tiene importancia! Cualquiera de ellos es un material y, por lo tanto, Copia podrá manejar cualquiera de ellos. Esta es una característica muy poderosa que nos permite modelar la propiedad de herencia de la orientación a objetos.

98

DEFINIENDO OPERACIONES EN EL MODELO Finalmente, vamos a completar otra característica importante del modelo. Debemos identificar cuáles son las operaciones más relevantes que cada clase debe cumplir, de acuerdo con las funcionalidades que se esperan del sistema. Recordemos, de acuerdo con lo que usted ha estudiado de la Programación Orientada a Objetos, que las buenas prácticas nos dicen que los atributos de las clases deben ser privados, es decir, ningún elemento de software externo a la clase puede tener acceso a dichos atributos. Solo se puede acceder a los atributos y modificarlos mediante operaciones. A su vez, a través de las operaciones, las clases exhiben un comportamiento, y dicho de una forma más útil para nuestros propósitos, aparte de exhibir un comportamiento, también ofrecen servicios. ¿Servicios en qué medida? En que una parte de las funcionalidades requeridas del sistema la cumplirán objetos de una clase particular y, por ende, tal cumplimiento se hará a través de las operaciones de las clases que actuarán convenientemente en colaboración con otras clases. Nuevamente, los casos de uso pueden ayudarnos a identificar qué servicios podría dar cada clase en el marco de lo que quiere implementarse como solución en el sistema. Para efectos de ilustrar esto, tomemos lo referente al escenario en la descripción detallada del caso de uso de Registrar Préstamo. El caso de uso comienza cuando el Bibliotecario ingresa al sistema la identificación del usuario. El Sistema le indica si el Usuario es válido. El Sistema, además le indica si el Usuario tiene algún registro de morosidad. Una vez comprobados los pasos anteriores, el Bibliotecario lee del Sistema Bibliotecario la información del material que va a prestarse, a través de un lector de código de barras. En ningún caso puede prestarse otra copia del mismo material al mismo usuario, lo cual se comprueba por parte del Sistema cuando se hace esta lectura. El Sistema indica si el material puede ser prestado solo para uso interno de la biblioteca y el tiempo que puede ser prestado en cualquier caso. El Bibliotecario registra el préstamo del material y el caso de uso termina. En el paso 1, vea que alguna clase debe indicar si un usuario es válido; esto significa que debemos averiguar el estado de un usuario en el Sistema. ¿Cuál clase tiene esa información? La clase Usuario. Por lo tanto, vamos a necesitar un método en dicha clase que nos indique el estado de un usuario. Dicho método u operación podría llamarse ObtieneEstado. De forma análoga, leyendo el paso 2, alguna clase en el sistema deberá indicar si un usuario es, o no es, moroso. Tal clase es RegistroMorosidad. Dicha clase tiene todos los registros que no han sido cancelados y, dichos registros, están 99

asociados a un usuario. La operación, suministrando la identificación del usuario, puede indicar si este último es moroso o no es, moroso. Esta operación, de tipo boolean, puede llamarse UsuarioMoroso. En el paso 3, una clase debe suministrar la información del material que va a prestarse. En este caso, tal información debería ser provista por la clase Material. Recordemos que si bien estamos tratando con una copia del material, a través de las relaciones, las clases incluyen objetos como atributos del tipo de otras clases. En este caso, la clase Copia incluye como atributo, un objeto de la clase Material. Tal operación en la clase Material puede llamarse ObtieneMaterial. Además, en la clase Préstamo debe existir una operación la cual, suministrando parámetros adecuados, como es la signatura y la identificación del usuario, averigüe si el usuario ya tiene prestada alguna otra copia del mismo material. Tal operación podría llamarse TieneCopiaPrestada. En el paso 4, se indican las condiciones del préstamo para un material. Esto, sin duda, lo suministra la clase CondicionesPrestamo. Pueden obtenerse tres métodos: ObtieneTipo (si es para uso interno o para préstamo externo), ObtieneTiempo, donde se indica la cantidad de tiempo que puede prestarse (un número entero positivo mayor que cero) y por último, ObtieneUnidad, que nos indicará si se presta por horas o por días. El paso 5 nos indica, efectivamente, que debe registrarse un préstamo. Esto debe hacerlo la clase responsable, la cual es Préstamo. El registro debe asociar al usuario, la copia que se presta y el bibliotecario que hace el trámite. Para ello también necesitamos, en su momento, las operaciones o métodos que nos den cada uno de los objetos de esas clases que se requieren para el registro. Tales operaciones son ObtieneCopia en la clase Copia; ObtieneBibliotecario en la clase Bibliotecario y ObtieneUsuario en la clase Usuario. Además, el objeto de la clase Copia debe actualizar su estado, mediante una operación llamada ActualizaEstado de disponible a prestada. Ya tenemos, por lo tanto, algunos métodos que nos pueden ayudar en una definición más amplia de las clases. Esto se resume en la siguiente tabla. Nombre de la clase Bibliotecario Usuario Material Copia Préstamo Registro Morosos Condiciones Préstamo

Operaciones o métodos ObtieneBibliotecario ObtieneUsuario, ObtieneEstado ObtieneMaterial ObtieneCopia, ActualizaEstado RegistraPréstamo, TieneCopiaPrestada UsuarioMoroso ObtieneTipo, ObtieneTiempo, ObtieneUnidad

Tabla Nº 7. Métodos identificados en cada una de las clases involucradas en el caso de uso de Registrar Préstamo.

100

Para seguir añadiendo operaciones, podemos revisar los escenarios de los otros casos de uso críticos del sistema: Registrar devolución y Registrar devolución con morosidad. En primera instancia, revisamos Registrar devolución. El caso de uso empieza cuando el Bibliotecario introduce el código del material que fue prestado mediante el código de barras. El Sistema registra la devolución e indica: “La devolución del (Libro / Revista / Video) xxxx fue registrada con éxito”. El paso 1 y el paso 2 parecen ocurrir de forma concurrente. El Sistema se prepara para registrar una devolución y lo que sucede es que recibe el código del material prestado e, inmediatamente, se registra la devolución, tal como se indica en el segundo paso. Por lo tanto, se requiere de una clase que se encargue de hacer el registro de la devolución. Eso correspondería a la clase Préstamo, que es la que tiene la información. Por sus atributos, para poder realizar la acción, dicha clase tiene la fecha de préstamo y las copias de los materiales prestados, entre los más importantes. Tal operación debe llamarse RegistraDevolucion. Esta operación debe recibir, como parámetro, la identificación del material devuelto y, con esa misma identificación, debe actualizarse el estado de la copia en la clase Copia con la operación ActualizaEstado que ya habíamos definido para esta clase. Revisemos ahora el escenario correspondiente al caso de uso Registra devolución con morosidad. El caso de uso empieza cuando el Bibliotecario introduce el código del material que fue prestado mediante el código de barras. El Sistema calcula el monto correspondiente por morosidad, de acuerdo con el tipo de material, las restricciones de uso y el retraso en tiempo. El Bibliotecario procede a dar “Aceptar” al registro de la devolución, visualizando el monto del cobro que se le realizará al usuario. El Sistema registra la devolución creando a su vez un registro de morosidad. El paso 1 no añade nada nuevo a las operaciones que hemos considerado anteriormente. El paso 2 indica que debe calcularse el monto de la morosidad. Acá enfrentamos una situación. O bien, le damos tal responsabilidad a alguna clase del modelo que ya tenemos, digamos, Préstamo, por cuanto tiene la fecha u hora de préstamo y la fecha u hora de devolución (de acuerdo al tipo de préstamo de que se trate); o bien, se puede pensar que se tiene una clase especializada en cuanto a calcular los costos de la morosidad.

101

Dicha clase tendría como atributos, los montos por morosidad por hora o día, y poseería operaciones para calcular el monto de morosidad, tal como indica el paso 2. Puede sugerirse, para conseguir mayor modularidad (esto lo veremos en el siguiente capítulo), optar por la opción de crear una nueva clase. A ella la llamaremos CostoMorosidad. El paso 3 indica que esa nueva clase debería tener una operación que permita obtener el monto calculado. Tal operación podría llamarse, ObtieneMonto. El paso 4 puede utilizar otra versión del método RegistraDevolución en la clase Préstamo. Esto es posible debido a que el paradigma de orientación a objetos, mediante la sobrecarga de operaciones, permite tener distintas versiones para un método con el mismo nombre. Además, debe registrarse la morosidad generada en la devolución, lo cual debe hacerse en la clase RegistroMorosos. Esta clase, por lo tanto, debe tener una operación llamada RegistraMorosidad. A su vez, deberá cambiarse el estado del usuario, situándolo a éste como usuario moroso. La clase Usuario, por lo tanto, debe tener una operación llamada ActualizaEstado. De esta forma, al analizar esos dos casos de uso adicionales, podemos obtener una lista de métodos u operaciones por clase, actualizada. En otro tipo de letra podemos visualizar las operaciones que se han agregado.

Nombre de la clase Bibliotecario Usuario Material Copia Préstamo Registro Morosos Condiciones Préstamo CostoMorosidad

Operaciones o métodos ObtieneBibliotecario ObtieneUsuario, ObtieneEstado, ActualizaEstado ObtieneMaterial ObtieneCopia, ActualizaEstado RegistraPréstamo, RegistraDevolución, TieneCopiaPrestada UsuarioMoroso, RegistraMorosidad ObtieneTipo, ObtieneTiempo, ObtieneUnidad CalculaMontoMorosidad, ObtieneMonto

Tabla Nº 8. Actualización de los métodos por cada clase en el Sistema de Préstamo Bibliotecario.

De esta forma podemos obtener un diagrama actualizado del modelo conceptual.

102

103

Figura 19. Diagrama del modelo de clases conceptual incorporando los métodos u operaciones por cada clase

En este último diagrama de la Figura 19, advierta que se han agregado las operaciones en las clases correspondientes. Además, se ha adicionado otra relación entre Bibliotecario y Préstamo, puesto que en distintos momentos uno o varios bibliotecarios actúan para registrar un préstamo (lo cual ya estaba) o para registrar en un préstamo, una o varias devoluciones. Detendremos acá el desarrollo del modelo conceptual. Nos hemos centrado, fundamentalmente, en obtener un modelo que pueda apoyar los objetivos del sistema para el préstamo y devolución de materiales bibliográficos, adicionando algunos controles, como es el registro de morosidad. Indudablemente, desarrollar otros casos de uso, es decir, otros objetivos del sistema y plasmarlos en el modelo de clases, aumentará, ya sea el número de clases, o bien los atributos y operaciones de las ya existentes. Recuerde que para algunos casos hemos hecho reflexiones (como el caso del registro de pagos), los cuales derivan en que se adicionen clases conceptuales al modelo. El proceso es laborioso y complejo, pero como lo habrá notado, es muy rico en descubrimientos a la luz de las reflexiones que se hacen sobre el problema que deba resolverse. Tal como hemos insistido a lo largo de este desarrollo, los casos de uso guían totalmente la elaboración de este modelo. Un hito importante del Proceso Unificado en la fase de Elaboración, es obtener una arquitectura sólida del sistema. La arquitectura debe ayudar a implementar los casos de uso. Al revisar el trabajo hecho en este capítulo, podrá darse cuenta cómo obtener este modelo puede aportar, e incluso, ser por sí mismo el hito que se busca en la fase de Elaboración. Con el insumo del modelo conceptual, podrá pasarse a la elaboración del modelo de clases de diseño. Esto lo trataremos en el siguiente capítulo.

104

EJERCICIOS DE AUTOEVALUACIÓN 1.

Comente, de forma justificada, por qué son relevantes los casos de uso en el desarrollo del modelo conceptual de clases.

2.

Sea un entorno de conceptos alrededor de la producción de obras musicales. Analice cuáles de los siguientes conceptos podrían corresponder a clases y cuáles a atributos. Cantante Canción Año de producción Álbum Género musical Número de canciones Productor Sello discográfico

3. Dentro de las clases conceptuales definidas en el ejercicio 2, establezca relaciones siguiendo la siguiente secuencia. a) Qué clases están potencialmente relacionadas. b) Dentro de cada par de clases, cuál clase requiere de la otra (puede ser que las dos requieran servicios de la otra). c) De un nombre a cada una de las relaciones (recuerde que debe hacerse en el extremo de la relación de la clase que sirve a la otra). d) Defina la cardinalidad de la relación. 4.

En el contexto de la producción musical, investigue de forma tal que usted pueda definir qué conceptos puedan establecer. a) Múltiples relaciones (2 o más) entre dos clases. b) Relaciones entre la misma clase. c) Considerando un proceso de venta de los productos musicales, defina una especificación de una clase.

Lea atentamente el siguiente planteamiento. El Ministerio de Cultura ha decidido, en conjunto con el Ministerio de Turismo, crear un kiosco electrónico donde un ciudadano o turista puedan consultar los espectáculos que se están ofreciendo en el Área Metropolitana. El kiosco ofrece la posibilidad de que la persona pueda navegar, buscando información de su interés, además de que pueda reservar el espectáculo que le atraiga. Tales espectáculos pueden ser de tres tipos: cine, teatro o deportes. Todos tienen características comunes, como horarios, localización, descripción del espectáculo, entre otros. Los de tipo teatro vienen con un video del director de la 105

obra, explicando sus aspectos. Los de cine tienen guardados textos con comentarios de asistentes y su nota, además de tres reconocidos críticos que también otorgan una nota. Los deportivos no presentan ninguna información adicional. Sin embargo, estos últimos ofrecen un regalo a las personas que reservan en línea. De acuerdo con lo planteado anteriormente, elabore lo siguiente: El Diagrama de Casos de Uso. Desarrolle con detalle el caso de uso referido a la reserva de un espectáculo. Extienda la definición anterior con respecto a la reserva de los tipos de espectáculos específicos (deportivos, de cine o teatro). Elabore el diagrama de clases conceptual que pueda implementar el caso de uso de reservar cualquier tipo de espectáculo. (Sugerencia: elabore su modelo siguiendo los pasos vistos en el capítulo. Además, debe aprovechar el mecanismo de herencia del Paradigma Orientado a Objetos).

106

CAPÍTULO

3

DE CARA A LA IMPLEMENTACIÓN: EL MODELO DE CLASES DE DISEÑO

Sumario CONSIDERACIONES PRELIMINARES

LA TRANSICIÓN DEL ANÁLISIS AL DISEÑO: LA VENTAJA DEL A/DOO TARJETAS CRC: DOCUMENTAR Y EVALUAR LAS CLASES CONCEPTUALES

LAS CLASES DE DISEÑO DEL NEGOCIO Refinamiento en la definición de atributos y operaciones Constructores Tipo de datos de los atributos Tipos de retorno y parámetros de las operaciones Relaciones de asociación y de composición: las relaciones conceptuales vistas en la óptica del diseño Diferencia entre relaciones de asociación y de composición Apuntes sobre la jerarquía de herencia

LOS GESTORES: ¿QUIÉN DIRIGE LA ORQUESTA? Arquitectura en n-capas Definir clases de gestión

107

OBJETIVOS Una vez que usted estudie este capítulo, podrá llevar a cabo cada una de las siguientes actividades de aprendizaje, que le servirán para comprobar cuánto ha aprendido de este tema -

Describir el proceso de la transición de un modelo conceptual a un modelo de diseño.

-

Explicar los conceptos de alta cohesión y bajo acoplamiento referidos a los modelos obtenidos mediante el Análisis Orientado a Objetos.

-

Indicar cómo se usan las tarjetas CRC para el proceso de definición de clases.

-

Explicar en qué consisten las clases de diseño del negocio.

-

Transformar una clase conceptual en una clase de diseño del negocio mediante la definición más precisas de las operaciones y los atributos, así como la definición de los constructores de las clases.

-

Diferenciar las relaciones de asociación y composición y su efecto en los atributos de las clases involucradas.

-

Analizar aspectos relacionados con la herencia, específicamente con las clases abstractas.

-

Explicar en qué consiste la arquitectura de n-capas en el marco del Análisis y Diseño Orientado a Objetos.

-

Justificar por qué son valiosos los casos de uso para la definición de las clases de diseño de gestión.

108

CONSIDERACIONES PRELIMINARES A través del estudio de este capítulo vamos a revisar varias actividades propias, relacionadas con generar un modelo de diseño para una solución de Ingeniería de Software utilizando el Diseño Orientado a Objetos. De forma general, si recordamos, el diseño tiene que ver con la definición de una estrategia para el proceso de implementación del software3. Al ubicar las fases genéricas de la Ingeniería de Software, un proyecto de esta disciplina debe pasar, entre varias actividades, por el análisis y diseño. Lo desarrollado hasta el capítulo anterior, estaría correspondiendo a las actividades de análisis: la identificación, definición y refinamiento de los casos de uso y del modelo conceptual han buscado proveer, precisamente, una definición de los requerimientos que busca implementar el sistema que necesita construirse. Uno de los retos más importantes que tiene la Ingeniería de Software es cómo adoptar los modelos generados en la fase de análisis, en la fase de diseño. Haremos, en primera instancia, una reflexión sobre el significado de esa transición en el A/DOO visualizándolo en el proceso, de una forma muy práctica. Posteriormente veremos cómo surgen necesidades de crear otras clases de cara al funcionamiento del sistema. LA TRANSICIÓN DEL ANÁLISIS AL DISEÑO: LA VENTAJA DEL A/DOO Cuando se han hecho tareas de Análisis con el objeto de identificar clases (desde el punto de vista conceptual), se buscó elaborar un modelo con elementos que trataran, en primera instancia, a responder a las necesidades de los objetivos del sistema. En este caso, se usaron intensivamente los casos de uso para ubicar conceptos, para crear las clases conceptuales pertinentes, para relacionar tales clases y caracterizar cada una de ellas a través de la definición de sus atributos y operaciones más importantes de cara a los requerimientos de cada caso de uso. El ejercicio de creación de esas clases, si lo notó, buscó que cada concepto, separadamente, estuviera bien definido en cuanto a sus características: los atributos y operaciones que deben tener, con el propósito de lo que cada clase debe cumplir en el Sistema. Incluso, en su momento en el ejemplo de la Biblioteca, llegaron a crearse clases, como la que se denominó CostoMorosidad, por cuanto se vio necesario que una clase pudiera cumplir con aspectos específicos de calcular lo relativo a los montos de morosidad dentro de la funcionalidad del sistema. Esa tarea no podía ubicarse en ninguna otra clase, o bien, si se hacía así, hubiera parecido algo artificial (por ejemplo, que fuera competencia de la clase Préstamo). 3

Puede consultar más teoría relativa a la Ingeniería del Diseño en Pressmann (2006), Ingeniería del Software. Un enfoque práctico.

109

Al definir clases bajo esa perspectiva, podemos relacionarlo con el conocido refrán popular de zapatero a tus zapatos. Con ello quiere decirse que cada clase que hemos definido cumple un rol muy específico dentro del sistema y que debe especializarse y saber solamente lo concerniente a ese rol. Por ejemplo, la clase Préstamo solo se dedica a registrar préstamo y la devolución de ese préstamo. Producto de ese conocimiento sobre los préstamos, se da cuenta que alguno de éstos está retrasado y se lo dice a Registro Morosos para que proceda esta clase a llevar a cabo lo que ella deba realizar. ¿Significa que la clase Préstamo debe saber cómo lo hace RegistrarPréstamo? No, no lo sabe. Solamente le dice “esta copia de material la devolvieron con retraso”. Definir clases de esta forma, encapsulando los atributos y operaciones que solamente conciernen a ella, estableciendo comunicación con otras clases mediante relaciones, persigue, en el fondo, que aparte de lograr cumplir con los objetivos requeridos del sistema, también pueda realizarse una transición hacia la fase de diseño de forma más “suave”. ¿Por qué? Porque cuando definimos clases de la forma que lo hicimos, podemos lograr encontrar que ellas puedan, eventualmente, cumplir con los principios en el diseño con respecto a la alta cohesión y el bajo acoplamiento. Recordemos brevemente estos conceptos: nos dice Pressmann (2006) que “una clase de diseño cohesiva tiene un conjunto de responsabilidades pequeño y enfocado, y aplica atributos y métodos de manera sencilla par implementar dichas responsabilidades”. ¿Hemos trabajado de esta forma con las clases conceptuales? ¿Cada una de ellas tiene un conjunto pequeño y enfocado de responsabilidades? ¿Se expresan esas responsabilidades de forma sencilla a través de atributos y métodos? Le queda a usted contestar si ello lo hemos logrado a través del ejercicio que hemos desarrollado. Mi criterio es que sí se ha hecho en gran medida así. Por otra parte, el mismo autor nos dice que acoplamiento bajo se refiere a que “dentro del modelo de diseño es necesario que las clases de diseño colaboren con alguna otra. Sin embargo, la colaboración debe mantenerse en un mínimo aceptable. Si un modelo de diseño tiene un acoplamiento alto (todas las clases de diseño colaboran con todas las otras clases de diseño), el sistema es difícil de implementar, probar y mantener a través del tiempo. En general, las clases de diseño deben tener sólo un conocimiento limitado de las otras clases”. De igual forma, observe que, si se visualiza el diagrama de clases conceptuales, las colaboraciones (expresadas como relaciones) que se dan entre clases, es el mínimo necesario para cumplir las metas del sistema. Vea que podemos, mediante el ADOO, ir cumpliendo con esos objetivos de alta cohesión y bajo acoplamiento de una forma muy natural, continuando con el proceso que seguimos en el capítulo anterior. En ese momento no hablamos de estos principios generales de la Ingeniería del Diseño. Lo que pasa es que elaborar clases bajo el análisis orientado a objetos, incorpora, desde ese 110

momento, principios relativos a la fase de Diseño, aun cuando solo estamos revisando conceptos, definiendo clases, atributos y relaciones a la luz de los casos de uso, es decir, actividades de muy alto nivel de abstracción. Larman (2003) nos indica que existe una reducción del salto en la representación. Siguiendo lo expuesto por este autor, cuando modelamos una clase conceptual esto obedece a que estamos acercándonos a modelar algo del mundo real. En el caso de nuestro Sistema de Préstamo Bibliotecario, si por ejemplo se sabe que un préstamo tiene una fecha o una hora en que un material se presta y que, además, el préstamo debe registrarse, entonces al elaborar la clase conceptual correspondiente, debe modelarse esta funcionalidad. Luego, al trasladarse esa clase conceptual, proveniente del análisis, hacia un modelo de diseño y este, a su vez, la realizamos en un lenguaje de programación particular, entonces obtendremos un producto de software que se concibió, en primera instancia, como conceptos y procesos del mundo real: un material bibliográfico, un préstamo, un registro de préstamo. En los siguientes diagramas y código de programación podemos ver esta evolución.

Préstamo

Copia - id_copia :

1..* Incluye

0..*

- Fecha : - Hora :

Representación conceptual

Copia - id_copia : String

Préstamo 0..*

1..* Incluye

+ ObtieneCopia () : Copia

- Fecha : Date - Hora : Time + RegistrarPrestamo () : int

Representación de diseño

Figura 20. Representaciones de la clase Préstamo y Copia en el modelo conceptual y en el modelo de diseño.

111

public class Préstamo { private Date Fecha; private Time Hora; public Copia[] Incluye; public int RegistrarPréstamo() { // debe implementarse el código acá return 0; } } Figura 21. Representación de la clase Préstamo en JAVA.

Note como todos los elementos se mantienen desde su origen como concepto y, lo que sucede en distintas etapas de la Ingeniería de Software, es un proceso de incorporación de aspectos propios de cada una de las fases. Es así como podemos comprender que un buen modelo conceptual es un paso muy importante que resulta en que la transición entre fases pueda ser, tal como lo mencionamos, “suave”. En la siguiente sección veremos uno de los aspectos derivados de esta transición. Vamos a definir de una forma más precisa los atributos y las operaciones del modelo conceptual, vistos ahora como clases de diseño. TARJETAS CRC: DOCUMENTAR Y EVALUAR LAS CLASES CONCEPTUALES En este punto, es una buena práctica constatar aspectos cohesión y acoplamiento de las clases conceptuales, mediante una revisión de las responsabilidades y servicios que da cada clase. Uno puede contar con mecanismos como las llamadas Tarjetas CRC (Clase-Responsabilidad-Colaborador) donde se establecen las responsabilidades y las colaboraciones por clase. Una tarjeta CRC es sencilla (como siempre, el “quid” del asunto es como usarla de forma apropiada). Para cada clase se define una estructura como la que sigue:

112

Nombre de la clase Descripción Responsabilidad

Colaborador

Como puede observarse, cada clase se describe brevemente en la sección descripción. Luego se establece una columna, donde se define qué responsabilidades asume cada clase y qué colaboradores (otras clases) debe tener para poder cumplir una responsabilidad específica. Por ejemplo, para la clase Préstamo podríamos establecer una tarjeta CRC de la siguiente forma.

Nombre de la clase: Préstamo Descripción: Clase que maneja los aspectos relativos al registro de préstamos de material bibliográfico y sus devoluciones. Responsabilidad Colaborador Registrar préstamos de materiales bibliográficos

Copia, Bibliotecario, Usuario, CondicionesPréstamo

Registrar devolución de materiales prestados

Copia, Bibliotecario

Detectar si una devolución está en mora Iniciar proceso de registrar una devolución morosa RegistroMorosos, Usuario, CostoMorosidad Indicar si ya un usuario tiene una copia del mismo material prestado

Usuario, Copia, Material

Este tipo de documentación es posible generarla cuando se ha tenido un proceso bastante alto de conocimiento del problema, mediante las actividades de análisis. Es deseable poder contar con este insumo cuando se inicia la fase de diseño, pues permite, por una parte, evaluar aspectos relativos a la cohesión y a la necesidad

113

de acoplamiento entre clases y, por otra parte, obtener un insumo de cara a la estrategia de implementación. No pierda de vista que las responsabilidades que asume la clase Préstamo son del dominio de su conocimiento. Si se incluyera la responsabilidad, por ejemplo de calcular el monto por mora, esta clase debería tener atributos que le serían conceptualmente ajenos, como el costo por retraso por unidad de tiempo (días u horas). Tal servicio lo asume, como ya se describió anteriormente, la clase CostoMorosidad. De asumir tal responsabilidad la clase Préstamo, se estaría incurriendo contra el principio de cohesión y el de acomplamiento. Con lo que se ha comentado en estos párrafos y con los conocimientos que usted debe manejar de los cursos de Análisis y Diseño, explique el porqué de la afirmación que se hizo. LAS CLASES DE DISEÑO DEL NEGOCIO Cuando se ha obtenido un modelo conceptual donde sus clases, atributos y operaciones clave están bien definidos, y ellas son altamente cohesivas y están débilmente acopladas, tal logro constituye un gran avance con miras al diseño. En tales clases deben tomarse algunas decisiones de cara a la implementación. Las clases conceptuales y su transformación en clases de diseño constituyen lo que se llama las clases de diseño del negocio. Esta denominación, muy ampliamente aceptada, se refiere a que se centran en los procesos de negocio que una organización quiere implementar, es decir, donde la semántica de las clases y de los procesos involucrados tienen una referencia a lo que Larman se refiere de que los modelos generados tienen una correspondencia en el “mundo real”. Por ejemplo una “copia de un material” existe en una biblioteca, así también un proceso de “registrar un préstamo”. Lo que hemos venido analizando, por lo tanto, corresponde a lo que es el “negocio” de una biblioteca. En una arquitectura estratificada o por capas, se estaría hablando con esta serie de clases de negocio, de la capa del negocio. Retomaremos lo referente a la arquitectura por capas más adelante.

Refinamiento en la definición de atributos y operaciones Volviendo a nuestro modelo, alguna de las decisiones más básicas con respecto a transformar las clases conceptuales en clases de diseño, tienen que ver con el tipo de datos de cada uno de los atributos, los parámetros de las operaciones, el valor de retorno de las operaciones, la necesidad de definir atributos de clase (que son globales a todos los objetos de una clase), entre varios aspectos puntuales que deben realizarse. Tomemos como ejemplo la clase Préstamo que es una de las clases medulares de nuestro Sistema en el ejemplo que hemos venido desarrollando relacionado con la

114

Biblioteca. Desde el punto de vista de nuestro modelo conceptual, hemos obtenido la siguiente definición para esta clase. Préstamo -

número_préstamo fecha_préstamo hora_préstamo tiempo_préstamo unidad_tiempo estado_préstamo

: : : : : :

+ RegistraPréstamo () + RegistraDevolución () + TieneCopiaPrestada ()

Debemos recalcar nuevamente que una tarea bien desarrollada en el modelo conceptual, facilita enormemente el trabajo de las clases de negocio en el modelo de diseño. Vea que el trabajo de clases conceptuales lo hemos realizado de cara a los objetivos del sistema y, por lo tanto, al ser retomadas en la fase de diseño, quedan pocas preguntas que hacerse con respecto a cuánto cumplen (o no) esas clases de cara a implementar el sistema. De esta forma, los diseñadores podrán ir concentrándose en aspectos de la definición técnica de la clase, de los detalles algorítmicos de las operaciones, de cómo lograr eficiencia, robustez y rendimiento del sistema, de cómo debe ser la interacción hombre/máquina, etc. Todo ello, en fin, buscando el reto más importante de la fase de diseño: la calidad del software. Volviendo a la clase Préstamo en este momento un diseñador puede ver la clase y hacer observaciones y preguntas tales como: Los constructores de clase, ¿cómo debo hacer tales constructores? ¿Debo inicializar todo los parámetros en null, o bien, necesito asignar algún parámetro con un valor determinado? ¿De qué tipo son los atributos? El número de préstamo ¿cómo lo genero? ¿Es un consecutivo normal, o bien es un correlativo con respecto a algo y todos los objetos de la clase deben mantenerlo (es decir, es un atributo de clase, no de objeto)? ¿Qué parámetros requieren las operaciones y qué tipo de datos devuelven? ¿Deben tenerse operaciones del tipo “actualizar/obtener” para todos los atributos? De esta forma puede comenzar a transformarse una clase conceptual en una clase de diseño. Si contestamos, a manera de ejemplo, cada una de las preguntas planteadas arriba, podríamos tomar algunas decisiones con respecto a la clase Préstamo.

115

Constructores Bien se sabe que toda clase debe tener, al menos, un constructor, que es una operación que permite crear los objetos pertenecientes a esta. Un constructor, por defecto, siempre crea un objeto con todos los atributos con valor nulo o null. En el caso de préstamo, ¿qué necesidad se tiene de tener constructores que no sea el constructor por defecto? Analicemos. Los atributos de la clase Préstamo están orientados a crear una transacción que debe registrarse en el momento preciso que esta ocurra, por ejemplo, la hora, el día, los materiales que se prestan, el tiempo de préstamo para cada material, el usuario asociado, el bibliotecario que ejecuta la acción. Por lo tanto, al imaginar la transacción, tal como sucede en el mundo real, uno podría tener una secuencia de pasos como la siguiente. 1. El bibliotecario elige la opción de “Registrar Préstamo” en el menú. 2. Se pide la identificación al usuario, se introduce y se verifica que tiene derecho a realizar solicitudes de préstamo. 3. Se incluye cada material solicitado en el préstamo. 4. Se hacen verificaciones por cada material prestado (por ejemplo que no tenga otra copia del mismo material prestada en este momento). 5. Se determina el tiempo de préstamo en cada material. 6. Se registra el préstamo. Al imaginar lo que sucede en el sistema (que quedará más claro cuando estudiemos los diagramas de secuencia), imaginamos lo que puede suceder en cada momento con operaciones que pueden estar en Préstamo. Revisamos a continuación cada paso. El bibliotecario elige la opción de “Registrar Préstamo” en el menú. Se utiliza el constructor por defecto de la clase y se tiene un nuevo objeto de la clase Préstamo. Se pide la identificación al Usuario, se introduce y se verifica que tiene derecho a realizar solicitudes de préstamo. Puede utilizarse el método de la clase Usuario para ActualizarUsuario en el atributo de usuario que debe tener, por asociación, la clase Préstamo4. Se incluye cada material solicitado en el préstamo. Con el lector de código de barras se obtiene la información de la copia de cada material. Cuando se creó el 4

Si bien ahora nos concentraremos en los atributos “propios” de la clase Préstamo, en un apartado más adelante veremos que las relaciones creadas en el modelo conceptual implican que Préstamo debe tener atributos de las clases con las que colabora, a saber, Usuario, Bibliotecario, Copia.

116

objeto de Préstamo, se debió crear una lista vacía de las copias del material por prestar. En este momento, se incluye, en la lista, cada uno de los materiales que se prestan. Por lo tanto, Préstamo debería tener una operación llamada IncluirCopiaEnPréstamo que actualice la lista de copias de materiales prestados. Se hacen verificaciones por cada material prestado (por ejemplo que no tenga otra copia del mismo material prestado en este momento). Se utiliza el método de la clase Préstamo de TieneCopiaPrestada con los parámetros de la signatura del material y la identificación del usuario. Se determina el tiempo de préstamo en cada material. Se obtiene el tiempo de préstamo del material mediante los métodos de la clase CondicionesPréstamo. Se registra el préstamo. Se utiliza el método RegistrarPréstamo. Sus parámetros deben ser el Bibliotecario que hace la transacción, el Usuario, la lista de materiales prestados, CADA UNO con el tipo de préstamo y el tiempo que se prestó. La fecha y hora de préstamo se obtienen de funciones del sistema como los pueden ser Today() y Now() que dan la fecha actual y la hora actual, respectivamente. Note que el ejercicio nos sirvió para muchas cosas, no solamente para aspectos relacionados con el análisis del constructor. Veremos, en un momento, que nos ha ayudado también a definir varios otros aspectos, entre ellos, una modificación al modelo de clases. El repaso también nos ha permitido comprobar que casi todos los atributos de un objeto de la clase Préstamo se obtienen en el transcurso del proceso de ingreso de la información del préstamo. De esa forma, casi no se ve necesidad de crear un constructor que no sea el constructor por defecto. Sin embargo, sí debe ponerse atención en el hecho de que la lista de copias de materiales por prestar debería estar creada (es decir, que no debe estar en null) para cuando reciba materiales. Por lo tanto, el constructor -por defecto- puede modificarse de forma tal que se inicialice para que la lista de materiales esté inicializada y, por ende, preparada para recibir ítems dentro de ella. Antes de seguir analizando las otras preguntas surgidas por parte de un diseñador, tenemos que ver una situación que arrojó el análisis anterior y que hace una modificación importante en nuestro modelo. Nos referimos a lo que se detectó con la frase “Sus parámetros deben ser (…) la lista de materiales prestados, CADA UNO el tipo de préstamo y el tiempo que se prestó”. Recordemos el análisis hecho con respecto a la devolución de materiales cuando analizábamos el modelo conceptual. Argumentábamos que no podía tenerse un estado global del préstamo, porque podría suceder que no todos pudieran devolverse al mismo tiempo. Ahora bien, uno podría suponer acá que para efectos del préstamo, todos los materiales van a tener la misma hora y fecha, los cuales son “globales” para todos los materiales dentro de la transacción. Tome en cuenta que, como todos son materiales distintos, cada uno de ellos tiene condiciones de préstamo diferentes. De esta forma, no puede suponerse que todos tienen el 117

mismo tipo y tiempo de préstamo, tal como lo indica el diseño actual. Por lo tanto, éste no responde a las necesidades de control que requerimos. Esto nos impulsa a que tengamos que hacer una modificación en nuestro modelo de clases, de tal forma que encontremos una nueva clase que pueda manejar, de forma individualizada, el tiempo de préstamo de cada uno de las copias de los materiales. Acá podría argumentarse que podríamos tener tales datos en CondicionesPréstamo. Pero puede suceder que en cualquier momento tales condiciones pueden variar, por lo tanto es necesario que otro elemento pueda ayudarnos a indicar las condiciones originales en las cuales se realizó un préstamo. Podemos tener, por lo tanto, una clase nueva en nuestro modelo, llamada DetallePréstamo, asociada a Préstamo y a Copia, donde se describen los detalles del préstamo de cada copia de material. El diagrama, en este punto, se modificaría así:

Bibliotecario - id_usuario : - nombre :

1..1 RegistraDevolución

+ ObtieneBibliotecario () 1..1 HechoPor

0..* 0..* DetallePréstamo Copia - id_copia : - estado_copia : + ObtieneCopia () + ActualizaEstado ()

1..1 Incluye

0..*

-

fecha_prestamo hora_préstamo unidad_tiempo fecha_devolución hora_devolución

: : : : :

Préstamo

1..*

-

1..1 Detalla

numero_préstamo fecha_préstamo hora_préstamo estado_préstamo

: : : :

+ RegistraPréstamo () + RegistraDevolución () + TieneCopiaPrestada ()

1..1 SeFundamentaEn

1..1 GeneradoPor

1..1

0..* Registro Morosos -

fecha_registro importe_moroso estado fecha_pago

: : : :

+ RegistraMorosidad () + UsuarioMoroso ()

Figura 22. Diagrama modificado al incorporar la clase Detalle Préstamo.

Observe que al asumir la clase DetallePréstamo un papel protagónico en el proceso, varias relaciones se modifican. En primer lugar, en relación con la clase Préstamo, esta nueva clase asume una relación de detallar, con respecto a las copias de los materiales que se incluyen. Este comportamiento, en mucho, es típico en los sistemas que vemos cotidianamente, por ejemplo, en una factura y 118

en cada una de las líneas de la factura, donde se detallan los productos adquiridos. O bien, un informe de matrícula, donde se detallan todos los cursos matriculados por un estudiante. Por otra parte, esta nueva clase va a tener los atributos correspondientes al detalle del préstamo de cada una de las copias de los materiales: así entonces tendrá la fecha y hora del préstamo, la unidad de tiempo (horas o días) y, además, manejará la fecha y hora de devolución. Esto la hará capaz de tener toda la información relativa a poder generar un registro de morosidad. Por lo tanto, vemos que la relación de RegistroMorosidad se hace directamente hacia esta nueva clase. La relación Préstamo/RegistroMorosidad tampoco será necesaria. Cada vez que se hace una devolución, el Bibliotecario registrará su acción directamente en el detalle. La tarjeta CRC que habíamos elaborado anteriormente para la clase Préstamo, cambiará las responsabilidades y colaboraciones de esta clase y, por otra parte, la clase DetallePréstamo asumirá nuevas responsabilidades, entre ellas, algunas que le correspondían a la clase Préstamo. Como ejercicio, usted puede elaborar las tarjetas CRC para estas dos clases.

Tipo de datos de los atributos Producto del cambio realizado, podemos dar un nuevo vistazo a la clase préstamo: Préstamo - numero_préstamo : : - fecha_préstamo : - hora_préstamo : + RegistraPréstamo () + RegistraDevolución () + TieneCopiaPrestada ()

Con una fisonomía más depurada, ahora podemos seguir con el ejercicio de incluir el constructor de la clase y, además, definir los tipos de datos de cada uno de los atributos. El atributo número_préstamo podría corresponder a un número consecutivo, o bien ser un número correlativo. Si fuera un consecutivo podríamos plantear que fuera un tipo de dato numérico normal, como un long. Sin embargo, si fuera correlativo, podría pensarse que fuera la composición de algo como: año + consecutivo. Podríamos ver el número de préstamo parecido a 2007000000001. En este caso, sería más aconsejable utilizar cadenas de caracteres, o el tipo String. Vamos a asumir la alternativa del correlativo. Para poder construir el correlativo, la clase Préstamo debería manejar dos atributos de clase, es decir, atributos que son vistos de forma global por todos los

119

objetos pertenecientes a la clase y, si alguno de estos objetos modifica ese atributo, el cambio es visible para todos los demás objetos. En este caso necesitamos los atributos de clase de Año y de Consecutivo en Préstamo (recuerde que deberán declararse con el modificador static, tratándose del lenguaje JAVA). El atributo Año lo llamaremos Anno, para efectos del manejo adecuado de un lenguaje de programación que no maneja bien la letra castellana eñe. Este atributo será de tipo entero. El consecutivo se llamará Consecutivo (se distinguirán atributos de objeto de los de clase en el modelo, dado que estos últimos iniciarán su nombre con mayúscula). En el momento en que se registra el préstamo, esta operación hará las conversiones necesarias de esos valores para que pueda componer el correlativo y asignárselo al atributo número_préstamo. Si el registro del préstamo tiene éxito, se aumentará en uno el atributo de Consecutivo y la próxima transacción de este tipo que realice cualquier otro objeto, utilizará ese número ya actualizado. El atributo fecha_prestamo se adjudicará un tipo de dato Date (fecha) y el de hora_préstamo asumirá, por su parte, un tipo de dato Time (hora). El atributo estado_prestamo podría ser de tipo char (caracter), manejando un dominio de valores significativos para sus estados: la letra ‘A’ para indicar abierto y ‘C’ para indicar que el préstamo ya está cerrado. Observe cómo la definición de los atributos se hace de acuerdo con alguna decisión relativa a la implementación. No es casual. Claro está que las facilidades que nos pueden ofrecer los lenguajes de programación ayudan a tomar estas decisiones. Por ejemplo, el hecho que JAVA provea un tipo de datos Date (fecha) es una ventaja para manejar atributos de esta naturaleza. Una visión actualizada de la clase Préstamo la veremos a continuación.

Préstamo : int : long : java.lang.String : java.util.Date : java.util.Time : char

-

Anno Consecutivo numero_préstamo fecha_préstamo hora_préstamo estado_prestamo

+ + + +

Préstamo () RegistraPréstamo () RegistraDevolución () TieneCopiaPrestada ()

Note cada uno de los atributos ya definidos en sus tipos. Por otra parte, dentro de los métodos ya se ha incluido el constructor (en JAVA, recuerde, los constructores son métodos u operaciones que se llaman igual que la clase). Advierta, además que los tipos en las clases de diseño se establecen de acuerdo con el lenguaje de programación específico que va a utilizarse. De ahí que, por ejemplo, fecha_préstamo especifique en su tipo, la ruta del paquete java.lang.Date.

120

Hasta este punto hemos agregado constructores, hemos definido los atributos e, incluso, hemos definido atributos de clase de acuerdo con las preguntas hechas por el diseñador. Pasamos ahora a definir aspectos relativos a las operaciones.

Tipos de retorno y parámetros de las operaciones La definición durante la fase de diseño incluye una especificación más precisa de las operaciones. Incluso, el diseño procedimental nos pide formular un detalle algorítmico de cada operación. Esto lo ilustraremos más adelante, cuando estudiemos los diagramas de actividad. Ahora vamos a enfocarnos en definir, dentro de la clase Préstamo, lo referente a los parámetros de cada operación y los tipos de retorno de cada una de ellas. Como ya vimos, la operación Préstamo es el constructor de la clase. Su papel es crear objetos de tipo Préstamo. No va a recibir ningún parámetro y, salvo la modificación anotada de inicializar, dentro de las acciones del constructor, una lista vacía para las copias del material que se deben incluir, se mantendrá el constructor estándar para la clase. La operación RegistraPréstamo deberá tener los siguientes parámetros: el Usuario que solicita el préstamo, el Bibliotecario que lo hace y la lista de materiales que van a prestarse. Puede tenerse un valor de retorno del tipo int (entero), para que el programa, analizando ese valor devuelto, pueda detectar alguna acción de error. Si no ocurre nada anómalo, la operación devuelve un valor de 0 (cero). La operación RegistraDevolución ya no sería responsabilidad de la clase Préstamo (analícelo a raíz de las tarjetas CRC que usted creó), sino que pasará a ser parte de las responsabilidades de la clase DetallePréstamo. Por otra parte, dentro del análisis de la secuencia de pasos que hicimos anteriormente, tuvimos la necesidad de crear una operación dentro de esta clase que añada ítems a la lista de copias de materiales que van a prestarse. La operación la llamaremos IncluirCopiaEnPréstamo. Esta operación recibe un parámetro, un objeto de tipo Copia, el cual se añade a lista de copias que contiene la clase Préstamo. Esta operación no devuelve ningún tipo de valor en particular. La operación TieneCopiaPrestada tendrá como parámetro la identificación del usuario y la signatura del material al que pertenece una copia. Devolverá un valor booleano, cuyo valor es verdadero si existe un préstamo activo de ese material relacionado con el usuario, o bien falso sino existe tal préstamo. Finalmente, en cuanto a las operaciones, debe establecerse si cada uno de los atributos tendrá una operación de Obtener y otra correspondiente de Actualizar. En general, es una práctica en la orientación a objetos, establecer operaciones para actualizar o dar valor a cada uno de los atributos, así como 121

también para obtener el valor de cada uno de dichos atributos. Esto por cuanto el acceso a los atributos solamente puede hacerse a través de operaciones. Sin embargo, no siempre esa regla debe cumplirse. Si se analizan cada uno de los atributos de los objetos (no los atributos de clase), podrá pensarse si ellos necesitan estas operaciones del tipo “actualizar/obtener”. En las de actualizar significa que puede cambiarse el valor del atributo en el momento que se requiera. Por ejemplo, número_préstamo es un valor transaccional generado por el sistema. De igual forma, la hora y fecha del préstamo se asignan automáticamente por la transacción. Por lo tanto, por control, estos atributos NO deberían tener operaciones de “actualizar”. Por su parte, en cuanto al estado del préstamo, sí podría actualizarse, pero de una forma muy específica: esto sería con la transición del estado “Abierto” al estado de “Cerrado”. Una vez que el préstamo presenta ese estado, no podrá actualizarse. La operación pertinente (ActualizaEstado) debe controlar esa situación. Las operaciones tipo “actualizar” reciben como parámetro un valor igual al del atributo. En este caso, si estado_préstamo es de tipo char, la operación recibirá un parámetro de este tipo5. En el caso de operaciones tipo “obtener”, no se encontraría ningún problema en poder saber cada uno de los atributos de los objetos. El tipo de valor de retorno de estas operaciones, correspondería al tipo de atributo sobre el que actúa. Por ejemplo, si número_préstamo es String, entonces la operación devuelve un String. Una clase de diseño para Préstamo, vista dentro del diagrama, con el trabajo realizado, luciría de esta forma:

Préstamo -

Anno Consecutivo número_préstamo fecha_préstamo hora_préstamo estado_prestamo

: int : long : java.lang.String : java.util.Date : java.util.Time : char

+ + + + + + + + +

Préstamo () RegistraPréstamo (Usuario pUsu, Bibliotecario pBib, Copia[] pCop) TieneCopiaPrestada (String pIdUsu, String pIdMat) IncluirCopiaEnPréstamo (Copia pCopia) ObtieneNúmeroPréstamo () : String ObtieneFechaPréstamo () : Date ObtieneHoraPréstamo () : Time ActualizaEstadoPréstamo (char pEstado) : char ObtieneEstadoPréstamo ()

Figura 23. Diagrama que muestra la clase Préstamo desde el punto de vista del diseño.

5

En la familia de lenguajes de programación orientados a objetos de .NET, las operaciones Obtiene/Actualiza se implementan mediante un mecanismo llamado property (propiedad). En el caso de que un atributo no pueda ser actualizado, tal como se discutió, la propiedad se dice que es Read Only (de “solo lectura”).

122

Si vemos el código en JAVA de la clase Préstamo, dicho código luciría así: import java.util.*; public class Préstamo { private static int Anno; private static long Consecutivo; private java.lang.String numero_préstamo; private java.util.Date fecha_préstamo; private java.util.Time hora_préstamo; private char estado_préstamo; public Préstamo() { } public RegistraPréstamo(Usuario pUsu, Bibliotecario pBib, Copia[] pCop) { } public TieneCopiaPrestada(String pIdUsu, String pIdMat) { } public IncluirCopiaEnPréstamo(Copia pCopia) { } public String ObtieneNúmeroPréstamo() { } public Date ObtieneFechaPréstamo() { } public Time ObtieneHoraPréstamo() { } public ActualizaEstadoPréstamo(char pEstado) { } public char ObtieneEstadoPréstamo() { return this.estado_préstamo; } }

Figura 24. La clase de diseño Préstamo, vista en código JAVA

123

Comparar lo que muestra una clase conceptual y lo que muestra una clase de diseño es importante. Cada trabajo tiene su momento. Cuando se crea la clase conceptual no deberíamos pensar en detalles como los que acá hemos abordado: tipos, parámetros, operaciones actualiza/obtiene, constructores, entre otros. En los modelos conceptuales no debemos molestarnos en cosas como esas, sino en descubrir aspectos relevantes del problema. Vea que lo que puede toparse un ingeniero de software en sus tareas de diseño, podría ser tratar con aspectos conceptuales que no se consideraron en su momento, o que no se detallaron más finamente, como lo que sucedió en nuestro trabajo con la clase CopiaPréstamo. Esto NO ES PECADO. Recordemos que durante todas las fases del Proceso Unificado persisten las tareas de requisitos, análisis, diseño. El modelo conceptual puede corresponder típicamente a la fase de elaboración del UP, mientras que el diseño corresponde ya a la fase de construcción. Sin embargo, realizar elaboración de requisitos y análisis no desaparece en ninguna fase. Sería lamentable que se arrastraran errores a etapas finales donde son más caros los cambios. Vea que nosotros “simplemente” modificamos el diagrama. Y sí, de verdad que fue simplemente así.

Relaciones de asociación y de composición: las relaciones conceptuales vistas en la óptica del diseño Cuando se creó el modelo conceptual de nuestro sistema de préstamo bibliotecario, se vio la necesidad de que algunas clases colaboraran con otras. Con ese propósito dibujamos algunas relaciones. Esas relaciones tienen un significado que, igualmente, tienen repercusiones desde el punto de vista del diseño. Revisemos nuestro diagrama, centrados en las clases que intervienen en los procesos de préstamo y de devolución:

124

1..1

1..1

fecha_registro importe_moroso estado fecha_pago

: : : : + RegistraMorosidad () + UsuarioMoroso ()

-

Registro Morosos

Préstamo () RegistraPréstamo (Usuario pUsu, Bibliotecario pBib, Copia[] pCop) TieneCopiaPrestada (String pIdUsu, String pIdMat) IncluirCopiaEnPréstamo (Copia pCopia) ObtieneNúmeroPréstamo () ObtieneFechaPréstamo () ObtieneHoraPréstamo () ActualizaEstadoPréstamo (char pEstado) ObtieneEstadoPréstamo ()

+ + + + + + + + +

125

Figura 25. Diagrama de clases de diseño involucradas en el proceso del préstamo de libros

+ ObtieneCopia () + ActualizaEstado ()

- id_copia - estado_copia

: :

1..1 SeFundamentaEn

0..*

Copia

: : : : :

1..* Incluye

0..*

fecha_préstamo hora_préstamo unidad_tiempo fecha_devolución hora_devolución

1..1 Detalla

-

DetallePréstamo

: int : long : java.lang.String : java.util.Date : java.util.Time : char

Anno Consecutivo número_préstamo fecha_préstamo hora_préstamo estado_préstamo

Prestamo

0..*

1..1 HechoPor

+ ObtieneBibliotecario ()

: :

-

1..1 RegistraDevolucion

Bibliotecario - id_usuario - nombre

: char

: String : Date : Time

0..*

1..1 Adjudica

+ ObtieneUsuario () + ObtieneEstado () + ActualizaEstado ()

: : :

Usuario - id_usuario - nombre - estado

Note que aún conservamos las relaciones que establecimos desde el punto de vista conceptual. Si usted recuerda, cuando las fuimos creando, se les sugería que estas fueran nombradas especificando el papel de la relación, es decir el nombre, en el extremo de la clase que era necesaria para la otra clase. En otras palabras, sabemos que la clase Préstamo requiere de la clase Bibliotecario y de la clase Usuario. Entonces, los nombres de las relaciones, como notará, están en el extremo de la clase que le es necesaria a Préstamo. Esto lo podemos ver en las otras relaciones: RegistroMorosos requiere saber cuál copia prestada en DetallePréstamo está generando la morosidad. DetallePréstamo requiere saber cuál es su préstamo y la copia del material asociada. Por eso los nombres de las relaciones se consignan en el extremo de las clases requerida por esta. Seguir esa sencilla regla permite a los diseñadores saber la “navegabilidad” de la relación. Los diseñadores van a ver el modelo y van a crear una relación específica, desde el punto de vista del diseño, llamada asociación. La asociación establece, en general, una clase que es cliente de otra. Esta última se dice que es una clase servidor. Si un diseñador ve esta situación en un diagrama:

Préstamo -

Anno Consecutivo número_préstamo fecha_préstamo hora_préstamo estado_préstamo

+ + + + + + + + +

Préstamo () RegistraPréstamo (Usuario pUsu, Bibliotecario pBib, Copia[] pCop) TieneCopiaPrestada (String pIdUsu, String pIdMat) IncluirCopiaEnPréstamo (Copia pCopia) : String ObtieneNúmeroPréstamo () : Date ObtieneFechaPréstamo () : Time ObtieneHoraPréstamo () ActualizaEstadoPréstamo (char pEstado) ObtieneEstadoPréstamo () : char

: int : long : java.lang.String : java.util.Date : java.util.Time : char

Usuario

0..*

1..1 Adjudica

- id_usuario : - nombre : - estado : + ObtieneUsuario () + ObtieneEstado () + ActualizaEstado ()

De inmediato va a saber que la clase Usuario es una clase cliente para Préstamo, pues se establece el nombre de la relación (adjudica) en el extremo de la clase Usuario. Las relaciones de asociación del tipo cliente/servidor se representan mediante una flecha, donde el extremo al que apunta la flecha es la clase servidor. Al seguir con el ejemplo, veremos entonces que el diagrama anterior se transformaría así:

126

Préstamo -

Anno Consecutivo número_préstamo fecha_préstamo hora_préstamo estado_préstamo

+ + + + + + + + +

Préstamo () RegistraPréstamo (Usuario pUsu, Bibliotecario pBib, Copia[] pCop) TieneCopiaPrestada (String pIdUsu, String pIdMat) IncluirCopiaEnPréstamo (Copia pCopia) : String ObtieneNúmeroPréstamo () : Date ObtieneFechaPréstamo () : Time ObtieneHoraPréstamo () ActualizaEstadoPréstamo (char pEstado) ObtieneEstadoPréstamo () : char

: int : long : java.lang.String : java.util.Date : java.util.Time : char

Usuario

0..*

1..1 Adjudica

- id_usuario : - nombre : - estado : + ObtieneUsuario () + ObtieneEstado () + ActualizaEstado ()

Vemos que en el extremo de Préstamo apunta la flecha de la asociación, por lo que se dice que DetallePréstamo navega en Préstamo. ¿Qué implica esto? Simplemente que en Préstamo debe existir un atributo de tipo Usuario que es el que implementa esta asociación. El código en JAVA que se genera a partir de esta modificación para la clase Préstamo, es el siguiente: public class Préstamo { private static int Anno; private static long Consecutivo; private java.lang.String numero_préstamo; private java.util.Date fecha_préstamo; private java.util.Time hora_préstamo; private char estado_préstamo; public Usuario Adjudica; Destacamos en letra negrita la inclusión del atributo de tipo Usuario, llamado Adjudica, tal como se consignó en el nombre de la relación. Posiblemente, para efectos del diseño, el ingeniero quiera cambiar ese nombre, no tanto para que sea significativo desde el punto de vista conceptual, sino para que tenga mejor legibilidad en la codificación. Personalmente estaría tentado a llamarlo simplemente usuario, lo cual debería modificarse, también, en el diagrama. Lo anterior por cuanto el proceso de diseño se hace mediante herramientas como Power Designer, que tienen la capacidad de generar el código de acuerdo con lo que se especifica en el diagrama. Una vista de esta característica de Power Designer, igual que otras que generan código a partir de la especificación del diseño, puede verse en la siguiente figura:

127

Figura 26. Vista de una ventana de Power Designer para la clase Préstamo.

La ventana anterior es la que maneja las propiedades de la clase Préstamo. Entre tantas cosas que pueden administrarse, están los atributos, las operaciones, las asociaciones, tal como usted puede ver en las “pestañas”. La pestaña que estamos viendo en este momento, es la que corresponde a Preview, la cual da una vista previa del código. Hacemos el paréntesis correspondiente en este momento de nuestro aprendizaje y reflexionaremos acerca del diseño de clases. Si bien este no es un libro que sea un instructivo de un paquete de software particular, sí es de destacar que los avances en la tecnología de los lenguajes orientados a objetos y del UML, han permitido crear herramientas que apoyan, de forma muy sustantiva, el proceso de análisis y diseño orientados a objetos. Dado este avance, traducir “lo que dibujo” en un lenguaje de programación es casi directo, gracias a la estandarización a la que se ha llegado en estas metodologías. Por lo tanto, en gran medida el proceso de trabajo “hormiga” se facilita mucho, dejando mayores espacios a la creatividad y el talento del ingeniero. Podemos modificar, por lo tanto, el diagrama anterior, estableciendo las relaciones de asociación que se dan entre las clases, considerando, de acuerdo con la guía que dimos, cuáles son las clases cliente y cuáles las clases servidor. Igualmente, se cambiarán los nombres de las relaciones con vista a cómo quieren que se llamen los atributos en las clases cliente.

128

Copia

+ ObtieneCopia () + ActualizaEstado ()

- id_copia - estado_copia

: :

1..1 préstamoMoroso

0..*

1..* copiasPrestadas

: : : : :

fecha_préstamo hora_préstamo unidad_tiempo fecha_devolución hora_devolución

1..1 copiaMaterial

-

DetallePréstamo

0..*

1..1

: : : :

Registro Morosos fecha_registro importe_moroso estado fecha_pago

+ RegistraMorosidad () + UsuarioMoroso ()

-

Préstamo () RegistraPréstamo (Usuario pUsu, Bibliotecario pBib, Copia[] pCop) TieneCopiaPrestada (String pIdUsu, String pIdMat) IncluirCopiaEnPréstamo (Copia pCopia) ObtieneNúmeroPréstamo () ObtieneFechaPréstamo () ObtieneHoraPréstamo () ActualizaEstadoPréstamo (char pEstado) ObtieneEstadoPréstamo ()

+ + + + + + + + + : char

: String : Date : Time

0..*

129

Figura 27. Diagrama de clases de diseño incorporando las asociaciones.

1..1

: int : long : java.lang.String : java.util.Date : java.util.Time : char

Anno Consecutivo número_préstamo fecha_préstamo hora_préstamo estado_préstamo

Préstamo

0..*

1..* bibliotecario

+ ObtieneBibliotecario ()

: :

-

1..1 bibliotecario

Bibliotecario - id_usuario - nombre

1..1 usuario

+ ObtieneUsuario () + ObtieneEstado () + ActualizaEstado ()

: : :

Usuario - id_usuario - nombre - estado

En el diagrama anterior, otra vez nos hemos centrado en el “subsistema” que maneja los préstamos y las devoluciones del material bibliográfico. Note cómo hemos transformado las relaciones conceptuales en asociaciones. Estas asociaciones, con su navegabilidad, vienen a concretizar la colaboración que debe existir entre las clases, exportándose de cada clase tipo servidor, un objeto de su tipo a la clase cliente. De esta forma, la clase cliente puede acceder a los servicios de la clase servidor, usando las operaciones provistas por esta. Veamos, por ejemplo, el código en JAVA resultante para la clase Préstamo, correspondiente a la parte de los atributos: public class Préstamo { private static int Anno; private static long Consecutivo; private java.lang.String número_préstamo; private java.util.Date fecha_préstamo; private java.util.Time hora_préstamo; private char estado_préstamo; private Usuario usuario; private Bibliotecario bibliotecario; private DetallePréstamo[ ] copiasPrestadas En letra negrita, de nuevo, destacamos los atributos resultantes de las relaciones definidas. Las decisiones en cuanto a diseño, incluso las que hemos puesto desde el modelo conceptual, influyen en mucha medida en lo que implica en las etapas de implementación. En este momento es normal que, realizando el diseño, tengamos un ojo en lo que pueden significar las cosas en la codificación, revisando constantemente el código que se genera en JAVA. Como parte de las decisiones de diseño, vamos a destacar, en este momento, la que se refiere a la cardinalidad de la relación. Vea que la relación de Préstamo hacia DetallePréstamo indica que Préstamo puede incluir n cantidad de copias de material. Por lo tanto, a diferencia de los atributos de Bibliotecario y de Usuario, que están relacionados con exactamente uno de cada uno de esos objetos, con copiasPrestadas, se establece un arreglo de objetos del tipo DetallePréstamo. Incluir un arreglo es la interpretación y la materialización de que un objeto de Préstamo manejará muchas copias de un material, los cuales se incluyen en objetos de tipo DetallePréstamo. En este caso, lo que se generó en el código JAVA es el resultado de una decisión de diseño hecha en el diagrama.

130

Diferencia entre relaciones de asociación y de composición Hasta ahora hemos visto que las relaciones que se han traducido del modelo conceptual, al modelo de diseño, se han visto como asociaciones. Ahora vamos a introducir conceptualmente las relaciones que son de composición y, una vez vistas, vamos a revisar las relaciones que tenemos en nuestro diagrama. Cuando establecemos una relación de asociación entre dos clases, este tipo de relación indica una colaboración que debe darse entre dos clases de una misma jerarquía, es decir, ninguna es más “importante” que la otra y, si bien se establecen necesidades, no hay ninguna dependencia que pueda notarse. Por ejemplo, una vez creado un objeto de tipo Préstamo, este permanecerá “vivo” e independiente con respecto de las clases con las que colaboró, por ejemplo Usuario o Bibliotecario. Lo anterior significa que, si por ejemplo, un Usuario después de cierto tiempo ya no está más afiliado a la Biblioteca, el objeto Préstamo que se creó en su momento existirá en el Sistema. Ahora bien, existen clases que dependen totalmente de otras en su existencia. Se establecen así jerarquías (que no son de herencia), en las cuales, la clase principal se dice que se compone de las clases dependientes. Las clases dependientes no podrían existir sin su clase principal. Estas relaciones se llaman de composición. Una composición que podríamos pensar muy naturalmente, es la que sería el CuerpoHumano. El cuerpo humano se compone de cabeza, brazos, piernas, y muchas otras partes, y cada una de ellas depende totalmente en su existencia, de la existencia del cuerpo. La composición se expresa por un rombo oscuro partiendo de la clase superior hacia las subordinadas. En nuestro ejemplo del cuerpo humano, veríamos algo así:

CuerpoHumano

1..1

1..1 posee Cabeza

1..1

1..1 posee Tronco

1..1

2..2 posee Brazos

La desaparición del cuerpo humano implica la desaparición de sus partes. ¿Cómo se vería la composición a nivel de código en JAVA en la clase CuerpoHumano? El código que se genera es el siguiente:

131

import java.util.*; public class CuerpoHumano { private Cabeza posee; private Tronco posee; private Brazos posee[2..2]; } Ahora vemos que, al igual que las relaciones de asociación, la composición genera atributos en la clase principal. Esto se asemeja a lo que sucede como consecuencia de una relación de asociación. En este punto usted se preguntará si lo que tenemos es algo meramente filosófico y, al final, todo puede resolverse de la misma forma, sea que uno defina relaciones de asociación o relaciones de composición. Sin embargo, aunque en apariencia sean parecidas las consecuencias en lo que la definición de las clases se refiere, el comportamiento va a diferir. ¿Cómo? En este caso, cuando se tiene una asociación, la clase cliente va a tener objetos de la clase servidor. En ningún caso, la clase cliente va a ser responsable por la creación de los objetos de las clases externas. Estos objetos deben ser creados y suministrados por algún proceso previamente. Por ejemplo, en el caso de Préstamo, cuando se está en el proceso de crear un registro de un préstamo, los objetos de Usuario y de Bibliotecario ya deben estar creados previamente en el sistema, antes de asociarlos al objeto que es de tipo Préstamo. Sin embargo, cuando se trata de una composición, el objeto de la clase principal es el encargado de crear los objetos que lo componen. Por lo tanto, sea en el constructor de la clase principal o en alguna otra operación de su clase, en algún momento se utilizará el constructor de las clases subordinadas para crear los objetos de estas clases que integrarán la clase principal. Lo anterior nos lleva a examinar la relación entre la clase Préstamo y la clase DetallePréstamo. Note que hasta el momento la hemos definido como una

relación de asociación. Sin embargo, podemos establecer, en primer lugar desde el punto de vista conceptual, que objetos del tipo DetallePréstamo están subordinados a la existencia de un objeto de la clase Préstamo. De tal forma que lo que se establece entre Préstamo y DetallePréstamo es una relación de composición, donde jerárquicamente, Préstamo es la clase principal y DetallePréstamo es la clase subordinada. Por otra parte, recordemos un par de detalles del proceso que revisamos cuando nos dispusimos a registrar un préstamo. En su momento habíamos indicado que el constructor de la clase Préstamo iba a crear una lista vacía de los objetos de la clase DetallePréstamo. Eso nos da una primera luz sobre la responsabilidad de Préstamo en lo que se refiere al manejo del detalle de las copias del material que va a prestarse. Por otra parte, en algún punto del proceso, debe crear un ítem de esa lista: eso significa que debe utilizar el constructor de la clase DetallePréstamo, proveyendo el código del material por 132

prestar y el tiempo de préstamo para éste. De tal forma que en este ejemplo se comprueba y se ilustra lo que mencionamos anteriormente sobre la responsabilidad de las clases principales, acerca de crear los objetos de las clases subordinadas. Podemos resumir, brevemente, las principales diferencias entre las relaciones de asociación y de composición: Tipo de relación Asociación Composición No existe una jerarquía en la relación de Se establece una relación jerárquica entre una clase principal y clases subordinadas. clases. La existencia de los objetos de las clases Los objetos de las clases involucradas no subordinadas depende de la existencia de dependen de la existencia de unas u otras. un objeto de la clase principal. El objeto de la clase servidor asociado en la clase cliente debe estar previamente La clase principal es responsable por la creación de los objetos asociados en ella creado. de las clases subordinadas. En cuanto a nuestro diagrama, debemos modificar la relación entre Préstamo y DetallePréstamo, vista en el diagrama 27, de la siguiente forma:

Préstamo

DetallePréstamo -

fecha_préstamo hora_préstamo unidad_tiempo fecha_devolución hora_devolución

: : : : :

1..* copiasPrestadas 1..1

+ + + + + + + + +

Anno Consecutivo número_prestamo fecha_préstamo hora_préstamo estado_préstamo

: int : long : java.lang.String : java.util.Date : java.util.Time : char

Préstamo () RegistraPréstamo (Usuario pUsu, Bibliotecario pBib, Copia[] pCop) TieneCopiaPrestada (String pIdUsu, String pIdMat) IncluirCopiaEnPréstamo (Copia pCopia) ObtieneNúmeroPréstamo () ObtieneFechaPréstamo () ObtieneHoraPréstamo () ActualizaEstadoPréstamo (char pEstado) ObtieneEstadoPréstamo ()

: String : Date : Time : char

Figura 28. Diagrama que muestra la modificación de la relación entre la clase Préstamo y DetallePréstamo.

En este caso vemos que se tiene la relación de composición entre esas dos clases. Posiblemente, el método IncluirCopiaEnPréstamo deberá ser el encargado de crear los objetos de tipo DetallePréstamo que se incluirá como ítem en la lista. En las relaciones jerárquicas de este tipo, existe una variante de la composición: la agregación. En este caso no hay un requerimiento tan fuerte como el hecho que la desaparición de la clase principal implique la desaparición de la clase subordinada. La forma de representar la agregación es mediante un rombo sin rellenar, partiendo de la clase principal hacia la subordinada. Un

133

ejemplo sería el concepto de un automóvil: un automóvil se compone de chasis, motor, llantas, entre muchos otros. En un diagrama conceptual lo veríamos así: Automovil

1..1

1..1

1..1 1..1 posee

1..1 posee

1..* posee Llantas

Chasis

Motor

Vea que, a diferencia de un cuerpo humano, que nace y muere como un todo, en un automóvil puede agregarse un motor ya existente, o bien, una llanta que ya tiene una existencia propia por aparte. Desde la perspectiva del automóvil, sin embargo, siempre es necesario crear los objetos de las clases subordinadas.

Apuntes sobre la jerarquía de herencia En la elaboración del modelo conceptual vimos algunos aspectos relativos a la herencia. Para la jerarquía de materiales bibliográficos, se definió una estructura como la siguiente: Material # # # # # # #

: : : : : : :

signatura copias_existentes copias_disponibles copias_prestadas año país idioma

+ ObtieneMaterial ()

Revista

Libro -

autor titulo ISBN editor páginas

: : : :

-

nombre volumen editor ISSN especialidad

: : : : :

Video + + + +

nombre productora director duración

: : : :

Figura 29. Diagrama que muestra la jerarquía de herencia del concepto de Material

Bibliográfico.

134

Cuando definimos los atributos, vimos algunos que eran comunes a todas las clases derivadas y otros específicos para ellas. Los atributos comunes son los que están en la superclase. Ahora bien, con las operaciones debe hacerse un ejercicio semejante. Tenemos que prever que tendremos operaciones que son comunes a todas las clases y otras que podrían ser específicas, o que si bien se definen de forma general, deben ser redefinidas en las clases derivadas, o bien otras que se definen de forma general pero que, en los niveles superiores de la jerarquía, no pueden dársele ninguna implementación y, por lo tanto, se ven como abstractas. Operaciones que pueden ser comunes y que nos presentan ningún problema potencial, pueden ser las del tipo Actualizar/Obtener en cada uno de los atributos de la superclase. Por ejemplo, una operación llamada ActualizarCopiasExistentes u ObtenerCopiasExistentes puede ser común a todas las clases derivadas y, ciertamente, todas van a usarlas. Ahora bien, en la superclase (es decir, la clase Material) puede definirse un método, el cual, dada una signatura de un material específico, indique la “longitud de la obra”. Tal operación puede llamarse LongitudObra. En este caso es una operación común para todas las clases derivadas: de acuerdo con los atributos, las clases derivadas que aplican para dar esa información son Libro (número de páginas) o bien, Vídeo (número de minutos). Quien no puede dar esa información es la revista, pues no tiene sentido en cuánto a páginas, dado que éstas se componen de artículos y otras cosas. Para ello, en la superclase puede definirse el método, retornando un valor de 0. Esa implementación de la superclase aplica muy bien para el caso de Revista. Sin embargo, las clases derivadas Libro y Vídeo tienen que redefinir esa operación, retornando los datos respectivos de páginas y duración. En este caso, se dice que estas clases sobrescriben la operación de la superclase (en inglés se dice override, que es la palabra clave en JAVA para implementar este mecanismo). Por último, si vemos el método que está en el diagrama de la Figura 29, ObtieneMaterial, la superclase no tiene conocimiento en ese momento de qué tipo de objeto retornar. Sin embargo, esta es una operación clave para todo el sistema. Al no tener tal conocimiento y, al saber que debe estar en todas las clases, tal operación se define como abstracta. Tal como usted sabe de sus conocimientos en programación orientada a objetos, cuando se define una operación abstracta en una clase, la clase por sí misma se vuelve abstracta. Y también se sabe que las clases derivadas están obligadas a darle una implementación a las operaciones abstractas (a menos que también mantengan tal operación abstracta con las implicaciones del caso, esto es, que ellas mismas serán clases abstractas). Por otra parte, también se sabe que no pueden crearse objetos pertenecientes a clases abstractas. ¿De qué me sirve entonces, a nivel de diseño, tener clases abstractas? Las clases abstractas permiten definir comportamientos esperados para objetos de una determinada clase. No se sabe a priori cómo estos podrán implementarse, pero son necesarios para cualquier clase que cumpla ser de la 135

superclase. Por ejemplo, para el Sistema Bibliotecario de Préstamos es necesario saber qué tipo de material va a prestarse. No se sabe a priori cuál va a ser, pero debe existir una operación en cualquier clase que cumpla ser material bibliográfico, que indique a las otras clases que lo requieran, qué tipo de material es. Tal operación podría llamarse ObtieneMaterial. De igual forma, se dice que una clase es abstracta cuando, necesariamente, la superclase no tiene conceptualmente sentido por sí misma y debe tomar forma en alguna de sus clases derivadas. Vemos que esto aplica muy bien en el caso del material bibliográfico: este solo tiene sentido si en algún momento lo identificamos como libro, o revista, o vídeo. Aun cuando sean clases abstractas, sí pueden establecerse relaciones de asociación con otras clases. Cuando se asocia un objeto de la clase Material, por ejemplo dentro de la clase Copia, deberá estar previamente definido como un objeto de la clase derivada a la que pertenece (Libro, Revista o Vídeo). Alguien debió usar el constructor específico de alguna de estas clases. Sin embargo, al tener la asociación definida en la superclase, esto permite obtener una posibilidad muy alta de extender las capacidades del sistema sin tener que afectar a todo el resto. Por ejemplo, si se agrega un material bibliográfico llamado Tesis derivado de Material, al resto del sistema le resultará transparente: siempre lidiarán con objetos que son materiales bibliográficos. Un resumen del diagrama de lo que hemos expuesto anteriormente, se ve a continuación. Material {abstract} # # # # # # #

signatura copias_existentes copias_disponibles copias_prestadas año país idioma

1..1 Concretiza

: : : : : : :

Copia : - id_copia - estado_copia : 0..*

+ ObtieneCopia () + ActualizaEstado ()

+ ObtieneMaterial () : Material : int + LongitudObra ()

Revista

Libro -

autor título ISBN editor páginas

: : : : :

-

nombre volumen editor ISSN especialidad

Tesis

Video : : : : :

+ + + +

nombre productora director duración

: : : :

+ LongitudObra () : int

-

estudiante gradoAcadémico garrera profesorGuía páginas

: : : : :

+ LongitudObra () : int

Figura 30. Diagrama que muestra la clase abstracta Material y las clases derivadas específicas de cada material bibliográfico.

136

Veamos el código en JAVA de la clase Material import java.util.*; public abstract class Material { protected signatura; protected copias_existentes; protected copias_disponibles; protected copias_prestadas; protected año; protected país; protected idioma; public abstract Material ObtieneMaterial(); public int LongitudObra() { return 0; } Figura 31. Representación en JAVA de la clase abstracta Material.

Vemos en el código de la clase (y en el diagrama de la Figura 30 también se identifica) que dicha clase es abstracta; lo que provoca que sea abstracta, específicamente, es el hecho de que el método ObtieneMaterial sea también abstracto. Veamos cómo se refleja en JAVA alguna de las clases derivadas, por ejemplo, la clase Libro: import java.util.*; public class Libro extends Material { private autor; private título; private ISBN; private editor; private páginas;

}

override public int LongitudObra() { return páginas; }

La palabra clave extends define la clase de la cual deriva Libro, en este caso Material. Además, mediante la palabra override se está sobrescribiendo el

método LongitudObra.

137

LOS GESTORES: ¿QUIÉN DIRIGE LA ORQUESTA? Hemos recorrido un largo camino para poder determinar un modelo de clases que, en primera instancia, nace como un proceso de dar forma a los conceptos inmersos en el dominio del problema. Iniciando con los casos de uso, se prosigue con las clases conceptuales. Se definen las colaboraciones entre ellas, los atributos y operaciones más relevantes para cumplir con los objetivos de los casos de uso, lo que nos lleva a obtener un modelo conceptual. Este modelo conceptual se transforma en un modelo de diseño, donde las clases conceptuales pasan a ser clases de diseño, obteniendo el modelo de clases del negocio. Cada clase se especifica mucho más finamente en cuanto sus atributos, operaciones y, por otra parte, se establecen a partir de las relaciones conceptuales creadas, las asociaciones y composiciones (o si es del caso, agregaciones). Llegados a este punto podría decirse que tenemos como una bodega llena de herramientas que podemos usar en un sistema. Pero, ¿cómo usarlas? ¿Cómo saber cómo llegar, por ejemplo, a crear un objeto de la clase Préstamo y posteriormente utilizarlo para registrar uno? ¿Cómo sé cuándo “disparar” una acción relativa a una devolución? ¿Qué debo tener en mi sistema para poder utilizar todo lo que hemos creado en las clases del negocio? Para poder realizar todo ese trabajo, debemos apelar a otras clases de diseño que nos van a ayudar. Estas clases las llamaremos gestores. Tales clases no están ligadas a un concepto propiamente dicho, como es el caso de Préstamo o Copia, sino que están creadas para administrar lo relativo a las acciones del sistema. Pressman (2006) las denomina como clases de proceso y las concibe como clases que “se requieren para manejar por completo las clases del dominio del negocio”. Larman (2005) las denomina controladores y los ubica para manejar los eventos del sistema. Ambas visiones coinciden, como vamos a ver, en el propósito que perseguimos descubrir en esta sección. Para ello nos sirve ubicarnos en el contexto de la arquitectura en capas. Vamos a realizar una breve conceptualización de esta arquitectura y cómo, a la postre, pueden ubicarse en ella nuestras clases del negocio y las que tenemos que crear a propósito de la gestión de éstas.

Arquitectura en n-capas Una arquitectura de este tipo busca dividir la acción de los elementos creados para un sistema en una serie de capas, los cuales parten de una visión de alto nivel, en este caso, la interfaz del usuario, descendiendo hacia otras capas de más bajo nivel, entre las cuales hallamos una referente al modelo del negocio y que culmina, finalmente, con la capa de base de datos. Tal modelo se inició con la arquitectura denominada Arquitectura de 3 capas: en primera instancia tenemos las clases de la capa que manejan la interfaz hombre/máquina; luego,

138

las clases de la capa del negocio y las clases que ayudan a manejar la interacción con la base de datos:

Capa de interfaz Capa del negocio Capa de interacción con BD

Base de datos

Figura 32. Arquitectura en 3 capas.

En la Figura 32 observamos cómo se crean 3 capas especializadas. La primera maneja las peticiones que surgen de la interacción de la interfaz “Hombre/Máquina”. A partir de esta interacción, por ejemplo, la petición de “Registrar un Préstamo”, estas clases llaman convenientemente a métodos de las clases del negocio que se requieren (digamos, los pertenecientes a la clase Préstamo). Finalmente, el registro de un préstamo tendrá que interactuar con la base de datos donde se almacenan los datos y donde se registran las transacciones del sistema. Esto se hace en una capa donde hay objetos de clases especializadas en la interacción con la base de datos y que son llamados desde las clases de negocio. Esta arquitectura fue muy popular en la medida que buscó administrar mejor la distribución de la computación cliente/servidor: se buscaba tener un cliente más “delgado” en la interfaz, utilizar un servidor de aplicaciones donde resida la lógica del manejo de la capa del negocio y el manejo de sus objetos y, finalmente, una capa que maneje todo los aspectos relativos a la base de datos. Sin embargo en esta arquitectura aún persiste una responsabilidad muy alta en la codificación de la capa de interfaz para el manejo de los eventos del sistema. 139

Esto hace que la dependencia del sistema con un objeto interfaz (por ejemplo, una ventana o una página HTML) sea muy alta, lo cual es indeseable de cara a la reutilización. Para evitar esto, entre la capa de interfaz y la capa de negocio se creó una capa de gestión de los eventos del sistema, donde hay objetos que, ante una petición específica de un usuario del sistema, los objetos en dicha capa saben cómo administrar esa petición independientemente del objeto de interfaz desde el cual se haga la solicitud. Estos últimos pueden ser objetos ventana, o bien páginas HTML, o un teléfono celular. Al independizar totalmente la interfaz de cualquier gestión de objetos de más bajo nivel en la arquitectura, se fomenta enormemente la reutilización. En esta visión, tendríamos algo una estructuración como lo que sigue.

Capa de interfaz

Capa de gestión de eventos

Capa del negocio

Capa de objetos de sistema Clases de interacción con BD

Base de datos

Figura 33. Arquitectura en n-capas.

140

En la figura anterior apreciamos cómo se crea una capa de la gestión de eventos entre la capa de interfaz y la capa del negocio. Al incluir esa capa, fomentamos una reutilización muy grande de los elementos de software del sistema. Propiamente, en la capa de interfaz se harían simplemente peticiones al sistema (vistas también como eventos) y dichas peticiones serían resueltas y coordinadas convenientemente por un gestor. De igual forma vemos cómo se incluye una capa de objetos del sistema. Esta capa manejaría acciones con elementos muy especializados, por ejemplo, hardware, comunicación remota con otros servidores, etc. Un ejemplo, en nuestro caso de la Biblioteca, podría ser la interacción con el lector de código de barras. Para ello, los fabricantes de tales equipos o sistemas deben proporcionar las especificaciones de cómo acceder al manejo de estos mediante lo que se denominan las Interfaces de Programación de Aplicaciones (más conocidas como API por sus siglas en inglés). La Figura 33 nos presenta una arquitectura de n-capas básica. De igual forma que se ha buscado independizar la capa de interfaz “Hombre/Máquina” añadiendo una capa de gestión, cada capa por sí misma puede crear otras capas por debajo de ellas, para lograr algún tipo de independencia requerida, transformándose plenamente en una arquitectura de múltiples niveles. Tales decisiones pueden tener que ver con independizar el funcionamiento del sistema hacia cualquier tipo de hardware, o bien, de cualquier tipo de ubicación física de uno o múltiples servidores. La complejidad puede aumentar bastante de acuerdo con los objetivos donde siempre se desprende aquella máxima: “tanto es más fácil para el cliente, tanto es más complejo para el proveedor”. De lo que hemos estudiado en cursos anteriores referente a la Ingeniería del Diseño, podemos visualizar en la Figura 33, finalmente, lo que Pressman (2006) describe como clases de diseño que este autor clasifica: ƒ

Clases de interfaz con el usuario

ƒ

Clases del dominio de negocios

ƒ

Clases de proceso (gestión)

ƒ

Clases de persistencia (bases de datos)

ƒ

Clases de sistema

Definir clases de gestión Existen algunos criterios de cómo definir estas clases de gestión. Los que están sugeridos por Larman (2003) pueden estar orientados en dos enfoques, a saber: Los gestores de “fachada”. En este caso, se crea una clase que contenga todos los eventos del sistema. Por ejemplo, tendríamos una clase que contenga los

141

métodos relativos a cualquier posible evento que podríamos imaginar que pueda tener nuestro sistema de préstamo bibliotecario: añadir materiales para préstamo, registrarlo, registrar una devolución, crear una morosidad, crear un material bibliográfico y una nueva copia para éste, entre muchos otros. Tales gestores son convenientes cuando hay un número limitado y pequeño de eventos en el sistema. Los gestores de casos de uso. Se toma el escenario de un caso de uso y se crea una clase con el sufijo “Manejador”. Se incluyen los métodos requeridos en el escenario provenientes de las clases involucradas en el escenario del caso de uso. Por ejemplo, podríamos tener una clase para el caso de uso RegistrarDevolución, la cual se llamaría RegistrarDevoluciónManejador. Esta clase la podríamos ver como: RegistrarPréstamoManejador + + + + + +

Préstamo () ActualizarBibliotecario () ActualizarUsuario () TieneCopiaPrestada () IncluirCopiaEnPréstamo () RegistraPréstamo ()

En ese caso vemos la serie de métodos necesarios como eventos del sistema que se requieren para poder manejar el caso de uso de Registrar un Préstamo de acuerdo al escenario del caso de uso. Crear gestores bajo la perspectiva de casos de uso son los mayormente recomendados. La discusión sobre los gestores la detendremos en este punto. Para completar una visión más amplia de su utilización, en el siguiente capítulo veremos cómo estos gestores resultan importantes en los diagramas de secuencia, los cuales vienen a redondear la visión de los modelos que hemos construido.

142

EJERCICIOS DE AUTOEVALUACIÓN 1. Explique el porqué, resultado de un buen análisis, la transición de las fases de análisis al diseño puede resultar “suave” producto del paradigma de Orientación a Objetos. 2. Retome el modelo conceptual creado para el problema de “Reservación de espectáculos en línea” y elabore lo siguiente. -

-

-

Documente las clases creadas con tarjetas CRC. A partir de ello determine y justifique si las clases definidas y documentadas son altamente cohesivas y bajamente acopladas. Plantee para las clases del modelo: Indique los constructores que requieren cada una de ellas. Los atributos de clase y los atributos de objeto, según corresponda, en cada una de las clases. Justifique las decisiones al crear un atributo de clase. Indique los constructores de cada una de las clases. Indique los métodos de actualizar/obtener para los atributos de las clases. Justifique en cada caso la decisión de diseño tomada. Revise el modelo conceptual creado para el Sistema de Reserva de Espectáculos en línea de tal forma que: Haga evidentes las relaciones identificadas se transformen en relaciones de asociación o de composición. Justifique el porqué en cada caso. Asegúrese de que pueda elaborar una jerarquía de herencia. Para tal caso, determine la existencia de una clase abstracta a partir de la cual las otras puedan derivarse.

3. De acuerdo con el planteamiento del problema del Sistema de Reservación de Espectáculos en Línea, existen varios dispositivos que pueden usarse en la solución, como es el caso de un kiosco. Suponiendo que este equipo es un hardware especializado, se le solicite que plantee de forma justificada, una arquitectura en n-capas para la solución requerida. Además, considere que el proceso de reservación requiere que la persona suministre la información de una tarjeta de crédito o débito para lo cual, también, se requiere que el sistema tenga alguna interfaz con el sistema bancario. 4. A partir del ejercicio anterior, explique qué se entiende como la capa de clases del negocio. 5. Explique para qué son las clases de diseño de gestión. ¿Cómo incrementan, este tipo de clases, la reutilización de las soluciones creadas?

143

6. Retome la descripción detallada del principal caso de uso identificado para el Sistema de Reserva de Espectáculos en Línea, para determinar un gestor para tal caso de uso. Identifique dentro de la clase que usted elabore, los métodos u operaciones necesarias para manejar los eventos del sistema que se definan. 7. Explique, de acuerdo a lo estudiado, ¿por qué los casos de uso son importantes en la definición de clases de diseño?

144

CAPÍTULO

4

EL MODELO DE INTERACCIÓN

SUMARIO CONSIDERACIONES PRELIMINARES DIAGRAMAS DE SECUENCIA: UN PRIMER ACERCAMIENTO Y SU UTILIDAD PARA DESCUBRIR LAS CLASES DE LA CAPA DE INTERFAZ Diagramas de secuencia de sistema Diagramas de secuencia: identificando la capa de interfaz Interacción entre capas: añadiendo la capa de gestión Cajas de activación y su efecto en las operaciones Visión del trabajo de los gestores en un diagrama de secuencia DIAGRAMAS DE ACTIVIDAD: APOYANDO LA ESPECIFICACIÓN DEL DISEÑO Elementos de un diagrama de actividad Especificación de casos de uso y diagramas de actividad Especificación de operaciones DIAGRAMAS DE ESTADOS Elementos de un diagrama de estados Elaboración de un diagrama de estados

145

OBJETIVOS Una vez que usted estudie este capítulo, podrá llevar a cabo cada una de las siguientes actividades de aprendizaje, que le servirán para comprobar cuánto ha aprendido de este tema -

Reconocer la utilidad de los diagramas de secuencia en las fases de análisis y diseño.

-

Construir diagramas de secuencia que representen la interacción entre los actores del sistema y el sistema.

-

Establecer la relación entre diagramas de secuencia y casos de uso para la definición de clases de diseño de las capas de interfaz y de gestión.

-

Refinar la estructura de las operaciones de las clases mediante la información suministrada por los diagramas de secuencia.

-

Definir, mediante los diagramas de secuencia, la interacción entre objetos requeridos para la solución de un objetivo del sistema.

-

Documentar gráficamente los casos de uso utilizando diagramas de secuencia y diagramas de actividad.

-

Expresar los algoritmos de una operación mediante los diagramas de actividad.

-

Definir los estados del sistema y las transiciones válidas en dichos estados mediante los diagramas de estado.

146

CONSIDERACIONES PRELIMINARES Conforme hemos ido avanzando en el desarrollo de nuestro modelo, se han ido incorporando elementos importantes bajo el paradigma de la orientación a objetos. Derivado de los conceptos identificados en los casos de uso, hemos encontrado los insumos para desarrollar el modelo conceptual reconociendo, precisamente, conceptos claves en el entorno del problema al que buscamos dar una solución. Tales conceptos iniciales evolucionan en su modelado bajo un análisis más detallado: se comienzan a identificar posibles clases conceptuales, las colaboraciones entre ellas vistas como relaciones, la cardinalidad de cada relación, las especificación de clases, la identificación de jerarquías de herencia, la definición de atributos y operaciones. Se incorporan nuevos casos de uso en el análisis de algunas situaciones del modelo y lo enriquecemos. Marcamos un hito en nuestro avance: logramos obtener un modelo de clases conceptuales consistente, que pueda apoyar los casos de uso. De esta forma podemos evolucionar y comenzar a construir un modelo de clases con definiciones, bajo la óptica del diseño. Se comienzan a incorporar algunas decisiones con vistas a la implementación: tipos de datos de los atributos, parámetros y tipos de retorno de las operaciones, definición de constructores de clases, entre muchas otras decisiones, las cuales, completan una visión hacia la implementación de las clases requeridas para la solución. De igual forma, a la luz de lo que plantea una arquitectura en capas, podemos incorporar otros tipos de clases que ayudarán a darle mayor robustez a nuestra solución. Tal es el caso de los gestores, los cuales buscan independizar la solución de la capa del negocio de aspectos específicos de la capa de interfaz. La capa del negocio se obtiene a partir de nuestro modelo de clases conceptual, el cual deriva en clases de diseño del negocio, o del dominio del negocio. La capa de gestión de eventos del sistema da respuesta a los usuarios del sistema sobre las solicitudes que dichos usuarios hagan desde la capa de interfaz, administrando la creación de objetos, la interacción entre éstos y la ejecución conveniente de operaciones de las clases. Igualmente, se aprecia una poderosa característica del A/DOO: los conceptos hallados en el mundo real se mantienen. Algo que se modela como Préstamo seguirá siendo el concepto de préstamo a lo largo del desarrollo. De igual forma, un caso de uso Registrar Préstamo, semánticamente definido en el contexto organizacional de la biblioteca que estamos usando de ejemplo, mantendrá ese significado en otros elementos de software que identificamos, como por el ejemplo, la clase de diseño gestor RegistroPréstamo_Manejador. De esta forma encontramos que evolucionar del análisis al diseño se hace de una forma muy “suave”. No debemos enfrentar tormentosos procesos, como se

147

daban en el análisis y diseño estructurado, para poder deducir del análisis al diseño, los modelos requeridos para la implementación del sistema6. Lo que hemos recorrido hasta este punto nos da una idea clara de los elementos requeridos para construir la solución. Es como ver, de alguna forma, el plano constructivo de una casa o edificio: vemos la distribución espacial de las cosas de una forma estática. Así también observamos nuestros modelos de clases: de una forma en que los elementos, por decirlo de alguna forma, están “quietos”. Sin embargo, puede interesarnos también encontrar alguna forma en que tales elementos puedan mostrar cómo interactúan entre ellos en un momento dado, a raíz de los eventos que puede desatar un usuario del sistema. Analizar tal perspectiva nos ofrecerá mucha información acerca de otras decisiones que debemos considerar para la especificación de nuestro modelo y del software que necesitamos construir. A continuación estaremos estudiando el tema de los modelos de interacción en el denominado diagrama de secuencia en UML. DIAGRAMAS DE SECUENCIA: UN PRIMER ACERCAMIENTO Y SU UTILIDAD PARA DESCUBRIR LAS CLASES DE LA CAPA DE INTERFAZ Los diagramas de secuencia son un tipo de diagrama en UML, los cuales permiten modelar la interacción surgida a partir de un evento en el sistema que desencadena un actor. Esas interacciones pueden verse en distintos niveles de refinamiento.

Diagramas de secuencia de sistema En primer lugar, puede servir para ilustrar la interacción entre el actor y el sistema, este último visto como una caja negra: no se conoce mayor detalle de lo que ocurre a lo interno del sistema. Simplemente, se visualizan las entradas y salidas que se dan en el contexto de lo que requiere hacerse por parte del actor. ¿Qué podría darnos un insumo para construir un diagrama de secuencia? Nuevamente recurrimos a los casos de uso. El escenario de un caso de uso muestra los pasos que deben darse en esa interacción entre el actor y el sistema. El diagrama de secuencia lo componen varios elementos: en la siguiente figura, observaremos un ejemplo básico de un diagrama de este tipo.

6

Usted podrá darse una idea de esto último consultando el Capítulo 10 de la versión en castellano del libro de Roger Presuman, Ingeniería del Software: un enfoque práctico, sexta edición. Las páginas a las cuales debe referirse van de la 297 a la 310.

148

Sistema Bibliotecario IngresaIdentificaciónUsuario

IndicaUsuarioVálido

IngresaMaterialPréstamo RegistraPréstamo

Figura 34. Representación de la interacción entre el actor Bibliotecario y el Sistema de Préstamo Bibliotecario, mediante un diagrama de secuencia.

Note los elementos del diagrama que aparecen en la Figura 34. En primera lugar, a la izquierda, encontramos un actor, tal como lo hemos visto en el diagrama de casos de uso. Específicamente vemos, en este caso, a un Bibliotecario que es actor de nuestro sistema de préstamo bibliotecario. Seguidamente vemos una caja, con el nombre Sistema. Al estar subrayado en este tipo de diagrama, significa que se está tratando con una instancia, o bien, con un objeto Sistema. Deberá existir un concepto o una clase llamada Sistema en el contexto de la solución que está desarrollándose. Debajo del actor Bibliotecario y del objeto Sistema “caen” unas líneas. Tales líneas podrán sustentar las interacciones que se tendrá entre el actor y el sistema. ¿Cómo es que estos interactúan? Ellos lo hacen mediante mensajes, que se representan por medio de una flecha que parte del actor y tiene su llegada en el sistema. Ese mensaje tendrá un nombre y los que se dirigen de izquierda a derecha (las entradas), se grafican con un trazo continuo. Los que van en el sentido inverso (las respuestas del sistema), tendrán un trazo discontinuo. Los mensajes se hacen en secuencia, de ahí el nombre de este tipo de diagrama: los mensajes se ejecutan en orden, de arriba hacia abajo.

149

Note algo muy importante. La secuencia de pasos que se diagraman se asemeja, en mucho, al escenario de un caso de uso. Si nos fijamos en el escenario del caso de uso de RegistraPréstamo, podemos encontrar tal semejanza. El caso de uso comienza cuando el Bibliotecario ingresa al sistema la identificación del Usuario. El Sistema le indica si el Usuario es válido. El Sistema le indica, además, si el Usuario tiene algún registro de morosidad. Una vez comprobados los pasos anteriores, el Bibliotecario lee del Sistema Bibliotecario la información del material que va a prestarse, a través de un lector de código de barras. En ningún caso puede prestarse otra copia del mismo material al mismo usuario, lo cual se comprueba por parte del Sistema cuando se hace esta lectura. El Sistema indica si el material puede ser prestado solo para uso interno de la biblioteca y el tiempo que puede ser prestado en cualquier caso. El Bibliotecario registra el préstamo del material y el caso de uso termina. Podemos, a partir de ello, comenzar a tener una visión interesante de, por una parte, documentar los casos de uso desde el punto de vista de la interacción del sistema y, por otra parte, comenzar a identificar una serie de mensajes que pueden ir tomándose en cuenta para crear algunas clases de diseño que más adelante veremos. A partir del escenario del caso de uso visto, podemos replantear el diagrama tomando como base la definición del escenario de dicho caso y, además, ver otros aspectos del diagrama.

150

Sistema Bibliotecario IngresaIdentificaciónUsuario

IndicaUsuarioVálido

IngresaMaterialPréstamo

VerificaMaterialNoPrestado IndicaMaterialYaPrestado

IndicaCondicionesPréstamo

Los pasos dentro del rectángulo se repiten

RegistraPréstamo

Figura 35. Representación del caso de uso Registrar Préstamo, mediante un diagrama de secuencia.

En primer lugar debe considerarse que se trata de poner, dentro del diagrama, los pasos y acciones estipuladas dentro del escenario del caso de uso. Aprecie que en el diagrama de la Figura 35 aparecen dos situaciones nuevas con respecto al anterior. En primer lugar, podemos ver que Sistema envía un mensaje a sí mismo. Allí se está indicando que, por sí mismo, el sistema debe verificar que un material solicitado por un usuario de la biblioteca no esté previamente prestado. Por otra parte, observe algo importante: cuando en un diagrama de secuencia usted halle un rectángulo encerrando varios mensajes, como sucede entre IngresaMaterialPréstamo e IndicaCondicionesPréstamo, entonces nos encontraremos en una serie de pasos que se repiten, es decir, una iteración o ciclo. Estos diagramas son relativamente sencillos. Podemos estructurarlos a partir de los casos de uso y nos pueden servir para identificar eventos del sistema que pueden darse en las clases de la capa de interfaz que analizamos en la arquitectura de n-capas. Por ejemplo, si tuviéramos una interfaz Web como la que presentamos a continuación, podríamos tener una situación como la que sigue.

151

Al ingresar el Bibliotecario el número de identificación del Usuario de la Biblioteca, a partir del evento generado en el botón Enviar, estaría evocándose a una operación que podría llamarse de igual forma, como se propuso en el diagrama de secuencia anterior: IngresaIdentificaciónUsuario.

Diagramas de secuencia: identificando la capa de interfaz ¿Qué eventos del sistema encontramos asociados con la interfaz de usuario a partir del diagrama de secuencia anterior? Obsérvelo. Podemos hallar los siguientes. IngresaIdentificaciónUsuario: recibiría el parámetro con la identificación de usuario. IngresaMaterialPréstamo: recibiría como parámetros el número de identificación de la copia del material y el tipo de material que se está prestando. RegistraPréstamo: recibiría los parámetros correspondientes a la identificación del usuario y la lista de copias por prestar. Así lograríamos tener una clase de diseño, correspondiente a la capa de interfaz, que podría llamarse RegistrarPréstamoInterfaz vista de la siguiente forma: RegistrarPréstamoInterfaz + IngresaIdentificaciónUsuario (java.lang.String pIdUsu) : String : String + IngresaMaterialPréstamo (java.lang.String pIdCopia, int pTipo) + RegistraPréstamo (java.lang.String pIdUsu, java.lang.String pIdBiblio, java.lang.String[] pCopias) : int

Al establecer un diagrama de secuencia utilizando esta clase, podemos formular nuevamente este de la siguiente forma.

152

:RegistrarPréstamoInterfaz

Bibliotecario IngresaIdentificaciónUsuario()

IngresaMaterialPréstamo()

RegistraPréstamo()

Figura 36.

Representación, en un diagrama de secuencia, del proceso de Registrar Préstamo, usando las operaciones de la clase de diseño de la capa de interfaz.

En este momento estamos ante otra situación respecto de la que vimos en el diagrama anterior. Precisamente, el anterior diagrama de secuencia de la Figura 36 está tratando con una visión de alto nivel de los eventos que se dan en un objeto de interfaz (una página, una ventana) y lo que el actor puede apreciar directamente en él. Sin embargo, en este último diagrama, estamos viendo la acción que se da, propiamente, en una clase de software correspondiente a la capa de interfaz que recibe el evento del sistema solicitado por el actor. Los tipos de retorno que incluimos en las operaciones, eventualmente serán los que usará el objeto interfaz, sea una página Web o una ventana, para poder responder al usuario. Por ejemplo, el String devuelto por la operación IngresaIdentificaciónUsuario, podría ser una cadena vacía (“ ”) que indicaría que no hay problema con el usuario, o bien, una cadena con un mensaje como “Usuario con problema de morosidad”. Por lo visto anteriormente, vemos una utilidad importante de los diagramas de secuencia en el proceso que hemos llevado hasta ahora con ellos. De una forma sencilla pudimos comprobar, en el contexto de un caso de uso, qué interacción podría existir entre un actor y el sistema. Posteriormente hemos visto cómo, a partir de esa interacción, puede deducirse una clase dentro de la capa de interfaz, la cual puede manejar, o mejor dicho, canalizar los eventos que desencadena el actor. Decimos canalizar porque, a partir de este punto, las operaciones de las clases de interfaz hacen intervenir a las clases de la capa de gestión de eventos, como veremos a continuación, mostrando que la sencillez de estos diagramas ilustran y hacen descubrir cosas muy valiosas en nuestro trabajo de diseño del software. 153

Interacción entre capas: añadiendo la capa de gestión Cuando analizamos la arquitectura de n-capas para introducir ciertas clases de diseño, estuvimos averiguando que este estilo arquitectónico fue concebido para independizar varios aspectos involucrados en una solución de software: la interfaz hombre/máquina, la acción sobre las bases de datos, las clases de diseño del negocio y los dispositivos de hardware que deben usarse eventualmente. Una de estas capas, la capa de gestión de eventos del sistema, se usa para poder lograr una independencia de la capa de interfaz con respecto a la capa de dominio de negocio. Al entrar “en juego” la capa de gestión, pueden obtenerse aspectos muy interesantes en perspectiva del comportamiento del sistema, ya que esta capa comienza a manejar la interacción que puede darse entre los objetos de la clase de negocio en perspectiva de dar la respuesta que desea el actor. Pero antes de entrar en esos detalles, observemos primero, cómo, mediante un diagrama de secuencia, puede apreciarse la interacción de una capa con otra, particularmente la capa de interfaz y la capa de gestión. Hemos visto que los diagramas que hemos desarrollado tienen algunos objetos involucrados: Sistema, en el primero, RegistrarPréstamoInterfaz, en el segundo. Cuando introdujimos el tema de los gestores, en el capítulo anterior, se propuso que estos podían llamarse igual que el caso de uso que manejarían y que al nombre del caso de uso se le añadiría el sufijo de Manejador. En el caso de nuestro ejemplo, un gestor que maneje el caso de uso de RegistrarPréstamo, pasaría a llamarse RegistrarPréstamoManejador. Al plantear la interacción entre capas, podemos toparnos con un diagrama como el que se muestra a continuación.

154

:RegistrarPréstamoInterfaz

:RegistrarPréstamoManejador

Bibliotecario IngresaIdentificaciónUsuario() ValidarUsuario()

IngresaMaterialPréstamo() TieneCopiaPrestada()

IncluyeMaterialPréstamo()

RegistraPréstamo() RegistraPréstamo()

Figura 37. Diagrama de la interacción entre la capa de interfaz y la capa de gestión.

En primer lugar, note que la acción entre capas se da mediante el envío de mensajes entre objetos que pertenecen a las clases de diseño involucradas. En este ejemplo, el Bibliotecario, como actor del Sistema, quiere registrar un préstamo. En primera instancia, el Bibliotecario, a través de algún componente de la interfaz (un botón de una ventana o página Web), genera un evento en el Sistema, el cual busca comprobar la validez de un Usuario ante el sistema de préstamos de la Biblioteca. El evento llamado se hace mediante la operación IngresaIdentificaciónUsuario. Esta, a su vez, llama a una operación en la capa de gestión de eventos, llamada ValidarUsuario. Lo mismo advertimos en los siguientes eventos que se dan para el registro de un préstamo: IngresaMaterialPréstamo, que llama a las operaciones TieneMaterialPrestado e IncluyeMaterialPréstamo. Por último, RegistraPréstamo llama una operación homónima en la clase de gestión.

Cajas de activación y su efecto en las operaciones Note que los mensajes, en este diagrama de la Figura 37, muestran una característica interesante: en la línea que desciende de la caja que representa 155

el objeto, notamos un rectángulo. Tal rectángulo se llama caja de activación. La caja de activación la utilizamos para poder visualizar cuándo empieza y cuándo termina la ejecución de un método y, durante su tiempo de vida, qué operaciones estará llamando para ejecutar. Esto último nos puede dar una idea de una parte de la codificación de las operaciones dentro de la clase. Por ejemplo, en el caso de IngresaMaterialPréstamo en la clase RegistraPréstamoInterfaz, en su código de programación necesariamente tendrán que haber llamados a los métodos de TieneMaterialPrestado e IncluyeMaterialPrestado de la clase RegistraPréstamoManejador. Esto significa que su código, debe tener un aspecto como el que sigue: public String IngresaMaterialPréstamo(String pIdCopia, int pTipo) { gestor.TieneMaterialPrestado(pIdCopia,pTipo); gestor.IncluyeMaterialPréstamo(idCopia,pTipo); return mensaje; } No se está diciendo nada en el código de programación anterior con respecto a la implementación final de esta operación. No obstante, lo que se trata de ilustrar, es el hecho de que este método debe realizar un llamado a esas operaciones del gestor. Con el diagrama de secuencia elaborado, podemos deducir, igualmente, el comportamiento que requerimos en la clase RegistraPréstamoManejador. De esta forma, un diagrama de la clase en cuestión lo podemos ver a continuación:

RegistrarPréstamoManejador + + + +

ValidarUsuario (java.lang.String pIdUsu) TieneCopiaPrestada (java.lang.String pSignatura) IncluyeMaterialPrestamo (java.lang.String pIdCopia) RegistraPrestamo (java.lang.String pIdUsu, java.lang.String pIdBib, Copia[] pCopias)

: char : int : int : int

El diagrama de secuencia nos ha servido para precisar nuestro gestor, el cual es una de las clases de diseño más importante en un modelo de arquitectura en ncapas. Por otra parte, note del código de programación que vimos anteriormente, que la clase RegistrarPréstamoInterfaz necesita tener un objeto de tipo gestor, con el fin de enviarle los mensajes que se requieren. Por lo tanto, estas clases están asociadas de la forma que se muestra a continuación (trate de contestar por qué se trata de una composición).

156

RegistrarPréstamoInterfaz + + + +

RegistrarPréstamoInterfaz (RegistrarPréstamoManejador pGestor) IngresaIdentificaciónUsuario (java.lang.String pIdUsu) : String IngresaMaterialPréstamo (java.lang.String pIdCopia, int pTipo) : String RegistraPréstamo (java.lang.String pIdUsu, java.lang.String pIdBiblio, java.lang.String[] pCopias) : int 1..1 1..1 gestor RegistrarPréstamoManejador + + + +

ValidarUsuario (java.lang.String pIdUsu) TieneCopiaPrestada (java.lang.String pSignatura) IncluyeMaterialPréstamo (java.lang.String pIdCopia) RegistraPréstamo (java.lang.String pIdUsu, java.lang.String pIdBib, Copia[] pCopias)

: char : int : int : int

Figura 38. Representación de la composición entre las clases de diseño de la capa de interfaz y de la capa de gestión.

De tal forma, el código en JAVA de la clase RegistrarPréstamoInterfaz se vería así: import java.util.*; public class RegistrarPréstamoInterfaz { private RegistrarPréstamoManejador gestor; public RegistrarPréstamoInterfaz(RegistrarPréstamoManejador pGestor) { } public String IngresaIdentificaciónUsuario(java.lang.String pIdUsu) { return null; } public String IngresaMaterialPréstamo(java.lang.String pIdCopia, int pTipo) { this.gestor.TieneMaterialPrestado(idCopia); this.gestor.IncluyeMaterialPréstamo(idCopia); return mensaje; } public int RegistraPréstamo(java.lang.String pIdBiblio, java.lang.String[] pCopias) { return 0; } }

157

pIdUsu,

java.lang.String

Observe del código de programación anterior, lo que se resalta en negrita. En primera instancia, que existe un atributo de tipo RegistraPréstamoManejador en la clase, debido a la dirección de la flecha en la composición. Por otra parte, el constructor de la clase RegistroPréstamoInterfaz deberá incluir un parámetro del tipo del gestor y mediante esta operación, a su vez, se encargará de crear, llamando al constructor de la clase RegistraPréstamoManejador, el objeto de este tipo que necesita en su clase.

Visión del trabajo de los gestores en un diagrama de secuencia Hasta este punto, con la ayuda de los diagramas de secuencia, hemos definido otras “clases de diseño” importantes, adicionales a las que trabajamos en el modelo de clases del negocio. Vemos, así la utilidad de este tipo de diagramas para poder descubrir las clases de gestión que necesitamos para manejar aspectos de la solución de software que requerimos. Veremos, ahora, qué interacción ocurre entre los objetos involucrados en la acción de RegistrarPréstamo. Para ello debemos adentrarnos, entonces, a un nivel más de nuestras capas: lo que ocurre en la capa de clases del negocio. En tal caso, podemos acudir y tener presente el ejercicio que utilizamos, cuando analizamos aspectos de la definición de constructores y operaciones de las clases de diseño del negocio, para poder ver la interacción que surge. De nuevo, ello tiene que ver con un escenario del caso de uso de RegistrarPréstamo. El bibliotecario elige la opción de “Registrar Préstamo” en el menú. Se utiliza el Constructor por defecto de la clase y se tiene un nuevo objeto de la clase Préstamo. Se pide la identificación al usuario, se introduce y se verifica que tiene derecho a realizar solicitudes de préstamo. Puede utilizarse el método de la clase Usuario para ObtenerUsuario en el atributo de usuario que debe tener, por asociación la clase Préstamo. Se incluye cada material solicitado en el préstamo. Con el lector de código de barras se obtiene la información de la copia de cada material. Cuando se creó el objeto de Préstamo, debió crearse una lista vacía de las copias del material por prestar. En este momento, se incluye, en la lista, cada uno de los materiales que se prestan. Por lo tanto, Préstamo debería tener una operación llamada IncluirCopiaEnPréstamo que actualice la lista de copias de materiales prestados. Se hacen verificaciones por cada material prestado (por ejemplo que no tenga otra copia del mismo material prestada en este momento). Se utiliza el 158

método de la clase Préstamo de TieneCopiaPrestada con los parámetros de la signatura del material y la identificación del usuario. Se determina el tiempo de préstamo en cada material. Se obtiene el tiempo de préstamo del material mediante los métodos de la clase CondicionesPréstamo. Se registra el préstamo. Se utiliza el método RegistrarPréstamo. Sus parámetros deben ser el bibliotecario que hace la transacción, el usuario, la lista de materiales prestados, CADA UNO con el tipo de préstamo y el tiempo que se prestó. La fecha y hora de préstamo se obtienen de funciones del sistema, como los pueden ser Today() y Now(), que dan la fecha actual y la hora actual respectivamente. Vamos a analizar esta secuencia detenidamente. El paso 1 indica que el bibliotecario debe elegir la opción “Registrar Préstamo” de un menú que se ofrece. Este servicio debería brindárselo una clase de la capa de interfaz, que le brindaría al bibliotecario la posibilidad de poder ingresar un préstamo en el sistema. Ahí se indica que, mediante el constructor de la clase Préstamo, se crea un objeto para ello. Pero, dado nuestro conocimiento en este punto, ¿qué es lo que realmente necesitamos? ¿Un objeto de la clase Préstamo? Para responder estas preguntas recordemos, antes, algunas situaciones. En primer lugar, ya vimos en su momento que no es conveniente que, desde la capa de interfaz, se manejen directamente aspectos relacionados con la capa del negocio. Para ello requerimos la acción de los gestores. Por otra parte, también debemos considerar que deben existir algunas validaciones previas a crear objetos de tipo Préstamo. Por ejemplo, cuando el caso de uso expresa en sus excepciones que: “de comprobarse que el usuario no está registrado en la biblioteca, el caso de uso termina”, estamos incurriendo en creación de objetos sin estar seguros de que van a ser utilizados. Si bien hoy en día contamos con equipos de hardware poderosos, no podemos menospreciar los costos computacionales incurridos en la creación de objetos, máxime que muchas veces las soluciones que brindamos (por ejemplo en un sitio de Internet) pueden atender a millones de usuarios, por lo cual la eficiencia es un objetivo que, como profesionales en computación, siempre debemos perseguir. Así que, como buenos diseñadores de software, todo lo que signifique ahorro será bienvenido (no olvide que diseño de software debe ser sinónimo de calidad). Todo ello nos lleva a pensar que lo que debe de crearse no es propiamente un objeto de tipo Préstamo, sino un gestor para RegistraPréstamo. En primera instancia se introduciría un objeto de tipo RegistraPréstamoInterfaz y, dentro de ello, se crearía el objeto de RegistraPréstamoManejador. Por lo tanto, la acción de que un bibliotecario elija la opción de registrar préstamo en un menú, podría verse de la siguiente forma (recuerde que los constructores de objetos de las clases llevan el mismo nombre de las clases).

159

MenuAplicación

:RegistrarPréstamoInterfaz

:RegistrarPréstamoManejador

Bibliotecario RegistraPréstamo

RegistrarPréstamoInterfaz() RegistrarPréstamoManejador()

Figura 39. Representación de la creación de objetos, a partir de la interacción entre capas.

Los siguientes pasos pueden analizarse a partir de la interacción de las clases pertenecientes al dominio del negocio. El paso 2 indica las comprobaciones con respecto a la acción del Usuario de la Biblioteca. Hasta este momento no se ha creado ningún objeto de tipo Usuario, por lo cual es necesario crearlo con su constructor. Puede crearse suministrando el número de identificación del usuario. Dicho parámetro es dado por el bibliotecario a través de los métodos de los gestores IngresaIdentificaciónUsuario, en la interfaz y ValidarUsuario en el gestor del caso de uso. Una vez creado, se procede a averiguar el estado del usuario con respecto al sistema. Si se comprobara que tiene el estado de moroso, no podría continuarse con el proceso. El paso 3 realiza acciones referentes al préstamo. Sin embargo, hasta este punto, por lo que hemos analizado, no se ha creado el objeto de la clase Préstamo. En este punto puede concebirse con toda propiedad, dado que se ha pasado la validación de que el usuario de la biblioteca está activo en el sistema y, por lo tanto, es el momento oportuno de contar con el objeto que maneja el préstamo. El paso 4 es complejo en su manejo, puesto que involucra varias acciones con objetos de la clase de negocio y de otras capas. En primer lugar, debe verificarse que el material que va a prestarse no tenga alguna copia, en este momento, prestada para el usuario. Para ello, el gestor debe crear un objeto de tipo Copia con el número de identificador suministrado por los métodos de los gestores (por ejemplo, IncluyeMaterialCopia en el gestor de la interfaz). Acá el gestor del caso de uso puede coordinar esta acción con un objeto de tipo LectorCódigoBarra, la cual es una clase de diseño, dentro de la clasificación vista, correspondería a una clase de diseño del sistema, es decir,

160

pertenecería a ese tipo de clases que manejan dispositivos especializados (como el código de barras) o bien, aspectos relacionados con el sistema computacional. El objeto de tipo Copia debe, por su parte, suministrar la signatura del material bibliográfico asociado a éste. Con la signatura y la identificación del usuario, la clase Préstamo invoca su propia operación de TieneCopiaPrestada. Ahora bien, ¿esta última operación es realmente de la clase Préstamo como lo hemos visto hasta ahora, o bien, debería pertenecer a otra clase? Para ello debemos preguntarnos ¿quién tiene la información de las copias prestadas? Y sí, naturalmente, usted al igual que yo, podremos darnos cuenta que la clase DetallePréstamo es quien posee tal conocimiento. Por eso mismo debemos crear en este punto un objeto de esta clase. Note también que, al querer plantear la secuencia del sistema a través del diagrama, nos damos cuenta de aspectos conceptuales y de diseño que deben resolverse de mejor forma. Acá, de nuevo, apelamos al espíritu iterativo del Proceso Unificado. Siguiendo con el paso 4, si el usuario no tiene una copia activa asignada en el préstamo, se procede con el paso 5, el cual consiste en averiguar el tiempo y tipo de préstamo que tiene este material. De igual forma podría usarse, para ello, operaciones en la clase Copia, la cual tiene el material asociado. Con estos datos, se procede a incluirlo dentro de la lista de materiales solicitados, lo cual se hace a través del método IncluirCopiaEnPrestamo. Finalmente, se registra el Préstamo con el método RegistrarPréstamo el cual es llamado por el gestor. Previamente deben asignarse la fecha y hora del sistema en cada uno de los registros de las copias prestadas. El diagrama de secuencia resultante, teniendo los gestores creados tal como vimos en el diagrama anterior producto del análisis del paso 1, podría ser el siguiente:

161

RegistraPréstamo()

IncluyeMaterialPréstamo()

ValidarUsuario()

:RegistrarPréstamoManejador

Préstamo()

RegistraPréstamo()

IncluirCopiaEnPréstamo()

ObtieneEstado()

Usuario()

:Usuario

TieneCopiaPrestada()

ObtieneSignatura()

Copia()

162

DetallePréstamo()

:Copia

ActualizaUnidadTiempo()

ObtieneUnidadTiempo()

ActualizaTipoPréstamo()

ObtieneTipoPréstamo()

ActualizaFechaPréstamo()

ActualizaHoraPréstamo()

ObtieneValor()

RegistrarTransacción()

:Préstamo

Figura 40. Representación completa del proceso de Registrar Préstamo, en múltiples capas

RegistraPréstamo()

IngresaMaterialPréstamo()

IngresaIdentificaciónUsuario()

Bibliotecario

:RegistrarPréstamoInterfaz

:DetallePréstamo

:LectorCodigoBarras

Le sugerimos que analice este diagrama, siguiendo el razonamiento de cada uno de los pasos que hicimos previo a este. Vea que se están identificando algunas nuevas operaciones en ciertas clases de la capa del negocio. Esto último, también es una riqueza que nos proporcionan los diagramas de secuencia. Podemos ver en el diagrama, de arriba hacia abajo, tres secciones bien delimitadas. La primera, lo relativo a la comprobación del usuario. La segunda, la cual al estar bajo un rectángulo, es repetitiva; se encarga de la inclusión de materiales y, por último, la sección relativa al registro del préstamo. Cada una de ellas parte de un evento que hace el Bibliotecario en su interacción con el Sistema. Por ejemplo, en cuanto a la comprobación del usuario, el bibliotecario, mediante la interfaz, llama a la operación IngresaIdentificaciónUsuario. Posteriormente, el gestor de caso de uso (RegistrarPréstamoManejador) invoca dos operaciones en la clase Usuario: Usuario, para crearlo y ObtieneEstado. Vea que esta parte del diagrama es consistente con el análisis que hicimos anterior a construir el diagrama.

Figura 41. Visión parcial de la figura 40 enfocada en la validación del Usuario.

Si bien en un diagrama de secuencia no se aprecian estructuras de control, como un if u otro tipo de condiciones, sí puede indicarse que de no tener éxito la comprobación del usuario, el resto de la secuencia no se ejecuta. Una segunda sección del diagrama de la Figura 40 representa las acciones que añaden copias de materiales en préstamo y la tercera el registro final del préstamo. De igual forma, debemos apreciar, observando de izquierda a derecha, que en este diagrama interactúan cuatro capas: la de interfaz, la de gestión de eventos, la de negocio y la de sistema. Implícitamente encontraremos una quinta capa: la de interacción con la base de datos.

163

La

de

interfaz

estaría

representada

por

el

objeto

de

la

clase

RegistraPréstamoInterfaz. La de gestión de eventos por el objeto de la clase RegistraPréstamoManejador. La de las clases de negocio está representada por las clases Usuario, Préstamo, Copia, DetallePréstamo. La de clases de sistema estaría representada por el objeto de la clase LectorCódigoBarras.

Implícitamente, también, al obtener la fecha y hora del sistema para actualizar la hora y fecha del préstamo, existe alguna clase que provea esos servicios (posiblemente facilitada por el API de JAVA), la cual entraría a ser parte de las clases del sistema.

Por último, advierta que Préstamo invoca una operación llamada RegistrarTransacción. Esta operación servirá para grabar, en una base de datos, los datos de la transacción de préstamo de materiales bibliográficos a un Usuario. Por lo tanto, esa operación deberá interactuar con alguna clase creada para dar los servicios de grabar acciones en la base de datos. Así, al ver la interacción completa, encontramos acción en 5 capas. Otro aspecto importante del cual nos valemos en los diagramas de secuencia, como mencionamos anteriormente, se refiere al descubrimiento de operaciones. Vea que previa a la elaboración de este, aún no conocíamos aspectos relativos a operaciones que debían ofrecer algunas clases. Eso es evidente en ciertas operaciones como los constructores (los cuales, por requerimiento del paradigma de orientación a objetos, todas las clases deben tenerlos). De igual forma, se han usado operaciones tipos Actualizar/Obtener en varios objetos. Dependiendo de la herramienta que se utilice, agregar nuevas operaciones en un diagrama de secuencia hará que estas, también, sean agregadas automáticamente en las clases involucradas. Por lo tanto, si se ha construido algún diagrama de clases como el que hicimos en el capítulo anterior, también se agregarán tales operaciones en este. Vea, por ejemplo, para las clases de DetallePréstamo cómo han sido actualizadas sus operaciones a partir de las que incluimos en el diagrama de secuencia de la Figura 40. DetallePréstamo -

fecha_préstamo hora_préstamo unidad_tiempo fecha_devolución hora_devolución estado_préstamo

+ + + + + +

DetallePréstamo () TieneCopiaPrestada (java.lang.String pIdUsu, java.lang.String pSig) ActualizaHoraPréstamo () ActualizaFechaPréstamo () ActualizaTipoPréstamo () ActualizaUnidadTiempo ()

: java.util.Date : java.util.Time : char : java.util.Date : java.util.Rime : char : java.lang.Boolean : int : int : int : int

Figura 42. Representación de la clase de diseño Detalle Préstamo, a partir de los descubrimientos derivados del diagrama de secuencia de la Figura 40.

164

Mediante Power Designer, todas sus operaciones fueron agregadas durante el trabajo que se hizo para construir el diagrama de secuencia de la Figura 40 anterior. Esto nos hace ver que los diagramas de secuencia tienen muchos usos en el análisis y en el diseño orientado a objetos. Gracias a ellos hemos podido ver y obtener lo siguiente. La interacción de un actor con el sistema. Esta es una interacción básica, que permite ilustrar lo que un actor podría esperar del sistema ante ciertas peticiones. No obstante ser un diagrama elemental, los diagramas de interacción del actor con el sistema, pueden deducirse a partir de los casos de uso y, con un trabajo especial, podemos conseguir, para cada uno de éstos, las clases de diseño relativas a la capa de interfaz. De igual forma, las clases de diseño de la capa de gestión de eventos del sistema (gestores), pueden definirse mejor a partir de descubrir, mediante la estos diagramas de interacción, las necesidades de la clases de la capa de interfaz con respecto a la de gestión. Los diagramas de secuencia permiten visualizar cómo interactúan los objetos de la capa de negocios, manejados a partir de un gestor. La interacción entre objetos permite también tener mejor idea de la definición de las operaciones a través de las cajas de activación. Todos los llamados que se ejecutan en una misma caja de activación permite a los diseñadores deducir qué operaciones deben ser llamadas a partir de una operación particular. Por ejemplo, la operación ValidarUsuario en RegistroPréstamoManejador, debe llamar a las operaciones Usuario y ObtieneEstado de la clase Usuario. Finalmente, no importando si se encuentra en labores de diseño o análisis, los diagramas de secuencia pueden utilizarse para descubrir nuevas operaciones en clases conceptuales o de diseño, por lo cual, en cualquier fase del proyecto, puede echarse mano de esta forma bastante poderosa de descubrir elementos de software en la solución que estamos elaborando. Algunas veces en el desarrollo de este libro hemos dicho frases como: esto quedará más claro cuando veamos diagramas de secuencia. Pues bien, eso significa que en esos momentos del trabajo, fuera que estuviéramos descubriendo clases conceptuales o clases de diseño, hubiera sido útil utilizar este tipo de diagramas. Ahora que usted los conoce, puede usarlos cuando convenga a su proyecto. Hemos llevado a cabo una serie de trabajos que nos permite obtener una visión y un modelo de clases de diseño más completo. Hemos obtenido clases referidas a las clases de la capa de interfaz, de la capa de gestión y de la capa del negocio. Hemos incluido también, una clase de la capa de sistema y hemos comentado algún aspecto de la capa de bases de datos. Por lo tanto, el avance que puede lograrse con los diagramas de secuencia, es notorio. 165

De igual forma vea que todo ello se ha conseguido centrándonos en un solo caso de uso, como es Registrar Préstamo. Por ello debemos tener en cuenta que agregar otros casos de uso permitirá, eventualmente, agregar muchas otras cosas a nuestro diseño. Y, por otra parte, vea cuan valioso es que usted sepa identificar cuáles casos de uso son críticos en el sistema. Ellos permitirán descubrir la arquitectura más importante en él. DIAGRAMAS DE ACTIVIDAD: APOYANDO LA ESPECIFICACIÓN DEL DISEÑO Recuerde usted que una de los propósitos principales de la Ingeniería del Diseño es poder proporcionar el llamado “diseño procedimental”. En términos sencillos, se trata de especificar los detalles algorítmicos de los procedimientos, funciones u operaciones que se ejecutan en un software. Dicha especificación se provee a los programadores, de tal forma que les sirva como base para la codificación que deba realizarse. Esta especificación puede darse de varias formas: pueden ser narraciones en “pseudo-código”, o apoyarse también en modelos gráficos, como los que proporciona UML. Teniendo esto en mente, podemos darnos cuenta de que los diagramas de secuencia nos sirven, de forma muy poderosa, para establecer varios requerimientos conceptuales (en las tareas de análisis) y de implementación (en las tareas de diseño). Sin embargo, para proporcionar un detalle procedimental como el que se necesita, si bien brinda algunas pistas importantes (como las operaciones que deben ser llamadas desde otra operación y el orden y momento en que deben llamarse dentro de ella o, también, las repeticiones de una parte del proceso), ciertamente no son suficientes para poder indicar todo el detalle algorítmico requerido para la especificación de las operaciones en las clases. La familia de diagramas de UML nos proporciona otro tipo de diagramas más adecuado para ello, conocidos como diagramas de actividad. Tales diagramas pueden representar, de forma más adecuada, detalles como verificación de condiciones, ciclos, cuándo puede terminar anticipadamente una ejecución; complementando muy bien lo que se descubre en los diagramas de secuencia y manejando aspectos que se especifican en los casos de uso (¡sí, nuevamente los casos de uso!). Por ejemplo, recordemos que los casos de uso establecen un apartado para excepciones, también llamados cursos alternativos. Pues bien, la visión de ello se materializa muy bien con los diagramas de actividad.

166

Elementos de un diagrama de actividad Si usted ya ha realizado alguna vez diagramas de flujo felizmente, los diagramas de actividad le resultarán familiares. Si no los ha realizado, felizmente no son complicados. Un diagrama de actividad se compone de los siguientes símbolos: Símbolo

Nombre Inicio

Señala el fin de un proceso que se ejecuta en el sistema.

Fin

Actividad

Propósito Señala el inicio de una proceso que se ejecuta en el sistema

Transiciones o flujos

Establece la transición que se da entre dos actividades

Actividad

Representa una actividad que se da en el sistema.

Sincronización

Decisión

Una barra horizontal recibiendo dos o más flujos o transiciones indica que las actividades de donde parten esos flujos deben ejecutarse paralelamente Un rombo define una decisión que debe tomarse a lo interno de un proceso en el sistema.

Figura 43. Símbolos usados en un diagrama de actividad.

Note que los elementos de un diagrama de actividad son sencillos y para usted, a esta altura de sus estudios, no le resultarán nada extraños. Como se mencionó anteriormente, se asemejan en mucho a los diagramas de flujo. Los diagramas de actividad son ideales para representar y especificar procesos que se ejecutan en el sistema. Pueden especificarse, desde aspectos de muy alto nivel, como lo casos de uso o lo que sucede en la interacción de un actor con el sistema, hasta cosas muy específicas como el detalle de una operación de una clase, o un algoritmo especial. Para ver su mecánica, partamos de un ejemplo sencillo: imagine que usted debe especificar un pequeño algoritmo que calcule la suma de los primeros n

167

números naturales. Una primera forma es realizar un ciclo que ejecute tal suma y eso lo veremos en el siguiente diagrama.

Obtiene número N

Declare variable contador i = 0

Declare variable acumulación suma = 0

Incremente en uno el contador

Actualice suma = suma más i

Retorne suma [i N]

Figura 44. Diagrama de actividad para un algoritmo, para calcular una suma de números naturales.

El proceso se inicia con una actividad “Obtiene número N”, la cual consigue el número N, que es el número máximo de la suma de los primeros N números naturales. Se ejecuta un proceso paralelo de declarar dos variables de trabajo: un contador llamado i (cuyo valor es 0 al inicio) y una variable suma donde se acumulará la suma (vea en el diagrama las actividades que hacen ello). Posteriormente, hay una actividad que incrementa en uno la variable i. Luego hay una verificación, donde se establece que si i es menor o igual a N, entonces se actualizará la variable suma con el valor en ese momento de la variable suma adicionando el valor de la variable i. Una vez hecha esa 168

actualización, se llama nuevamente a la actividad de acumular en uno el contador i. Observe que el proceso descrito en el párrafo anterior se repite hasta que, finalmente, la variable i es superior a la variable N. Una vez que i supera este valor, el proceso retorna el valor acumulado en la variable suma y el proceso termina. El ejemplo anterior nos sirve para ilustrar la capacidad que tiene un diagrama de actividad para especificar condiciones (o decisiones) y para visualizar, también, ciclos de repetición. Estos pueden ser fácilmente representados en estructuras de control de lenguajes de programación, como instrucciones if, o bien for, while o do-while en JAVA. Para quienes tienen curiosidad matemática, la suma de los primeros N números naturales también pueden calcularse de una forma muy directa. Dicha suma corresponde a la multiplicación de (N * (N + 1)) / 2. Formule, como ejercicio, en un diagrama de actividad sencillo, este cálculo.

Especificación de casos de uso y diagramas de actividad Cuando se especifican casos de uso empleando los diagramas de secuencia, podemos observar lo que podría pensarse que es el “curso normal de eventos”, es decir, que ocurren cada uno de los pasos previstos en el escenario como se espera que pasen, sin que suceda ninguna excepción o curso alternativo. Sin embargo, como ya se mencionó, puede ocurrir que en algún momento de la ejecución del caso de uso surja algún tipo de situación que no permita que se ejecute el siguiente paso, pudiendo resultar, además, que el caso de uso termine, dada una situación particular, y no se logre el objetivo que se perseguía obtener. La carencia señalada anteriormente, de los diagramas de secuencia, por no representar estas situaciones, puede solventarse con lo que puede expresar un diagrama de actividad. Como veremos a continuación, estos pueden completar la especificación de lo que sucede en un caso de uso. Tomemos, de nuevo, el ejemplo que corresponde al caso de uso de Registrar Préstamo. Recordemos, a continuación, su descripción detallada.

169

Caso de uso Objetivo

Registrar préstamo Registrar la información del préstamos de un material bibliográfico que se le hace a un Usuario de la biblioteca de la Universidad Actores Bibliotecario Condiciones previas El Bibliotecario deberá tener en sus manos el material por prestar, ya sea que el Usuario se lo haya proporcionado, o bien que él mismo haya tenido que buscarlo, dado que es de préstamo restringido. Además de contar con la identificación del Usuario que lo habilite para poder usar el servicio de Biblioteca. Escenario El caso de uso comienza cuando el Bibliotecario ingresa al sistema la identificación del Usuario. El Sistema le indica si el Usuario es válido. El Sistema, además le indica si el Usuario tiene algún registro de morosidad. Una vez comprobados los pasos anteriores, el Bibliotecario lee, del Sistema Bibliotecario, la información del material que va a prestarse, a través de un lector de código de barras. En ningún caso puede prestarse otra copia del mismo material al mismo Usuario, lo cual se comprueba por parte del Sistema cuando se hace esta lectura. El Sistema indica si el material puede ser prestado solo para uso interno de la Biblioteca y el tiempo que puede ser prestado en cualquier caso. El Bibliotecario registra el préstamo del material y el caso de uso termina. Excepciones o cursos En el paso 1, de comprobarse que el Usuario no está registrado alternativos en la Biblioteca, el caso de uso termina. En el paso 2, si el Usuario está moroso, el caso de uso termina. En el paso 3, si el código de barras del libro esté ilegible, el Bibliotecario deberá ingresar este directamente en un campo de edición de la pantalla. En el paso 3, de comprobarse que el Usuario ya tiene una copia del mismo material asignado en otro préstamo, el caso de uso termina. En el paso 4, luego de indicarle al Usuario las restricciones del préstamo, éste puede decidir no aceptar las condiciones, por lo cual el Bibliotecario termina la ejecución del caso de uso. Condiciones posteriores De cumplirse el paso 5, el Sistema guarda el registro del préstamo efectuado al Usuario. El material debe quedar en estado de “prestado”.

Note que en la descripción se establece una secuencia de 5 pasos en los cuales pueden inferirse actividades. Por ejemplo, en el paso 1 se indica que: “El caso

de uso comienza cuando el Bibliotecario ingresa al Sistema la identificación del Usuario. El Sistema le indica si el Usuario es válido”. Ahí podemos encontrar

varios elementos que nos pueden servir para nuestro diagrama de actividad. Por una parte se establece claramente un inicio y cuál actividad se ejecuta

170

primero (el caso de uso comienza cuando el Bibliotecario ingresa la identificación del Usuario). Por lo tanto, en un primer momento, podemos tener una construcción como la que sigue:

Bibliotecario ingresa identificación del usuario

Advierta también que se está estableciendo, en las excepciones del caso de uso, una específica para el paso 1, la cual establece que: En el paso 1, de

comprobarse que el Usuario no está registrado en la Biblioteca, el caso de uso termina. Dado el conocimiento que tenemos ya del Sistema, no solamente es

el hecho que esté o no registrado en el Sistema, sino también que pueda estar moroso o no estarlo. Todo ello debe averiguarse en la siguiente actividad del proceso e, igualmente, debe hacerse una comprobación que podría dar por terminado la ejecución del caso de uso. En otro caso se seguiría con la siguiente actividad descrita en el paso 3: obtener el código del material en préstamo usando el lector código de barras. Vamos a visualizar cómo iría resultando, hasta este punto, nuestro diagrama.

Bibliotecario ingresa identificación del usuario

Comprobar la validez del usuario

[Sí] Leer código de barras del material

[No] Usuario Valido

Figura 45. Primera elaboración del diagrama de actividad para el caso de uso de

Registrar Préstamo.

Posteriormente, con respecto al paso 3 y relacionado con la lectura del código de barras del material bibliográfico, puede surgir una excepción: que este no pueda leerse mediante este dispositivo. Por lo tanto, también debe darse una verificación si pudo leerse o no fue posible leer el código de barras del 171

material. Si la respuesta es afirmativa, se prosigue, de lo contrario, el bibliotecario tendrá que ingresar dicho código mediante el teclado. El diagrama se vería de esta forma.

Bibliotecario ingresa identificación del usuario

Comprobar la validez del usuario

[Sí] Leer código de barras del material

[No] Usuario Válido

Código leído

[No]

Ingresar código material con teclado

[Sí]

Comprobar material para préstamo

Figura 46. Continuación de la elaboración del diagrama de actividad para el caso de uso de Registrar Préstamo.

En el diagrama de la Figura 46 anterior vemos cómo, una vez que se comprueba que ha podido leerse (o que no ha podido leerse) el código del material con el lector de código de barras, se pasa a la actividad de comprobar el material para préstamo. Fijémonos bien en la excepción que se enunció originalmente: “En el paso 3, de comprobarse que el Usuario ya tiene una copia del mismo material asignado en otro préstamo, el caso de uso termina”. De nuevo, debemos pensar en la evolución que ha tenido nuestro conocimiento del sistema y lo que se ha resuelto (en teoría) junto con el cliente.

172

Sabemos que por cada préstamo puede haber muchos materiales que pueden prestarse. Por lo tanto, lo que se expresa en esa excepción ya no es válido y debería modificarse. Pareciera que en el momento en que se escribió ese caso de uso, se pensaba que solo podía haber un material prestado por préstamo. Por consiguiente, tanto el paso, como la excepción, deberían modificarse como sigue. “Una vez comprobados los pasos anteriores, el Bibliotecario lee del Sistema Bibliotecario la información del material que va a prestarse, a través de un lector de código de barras En ningún caso puede prestarse otra copia del mismo material al mismo usuario, lo cual se comprueba, por parte del Sistema, cuando se hace esta lectura El proceso se repite por cada uno de los materiales que el Usuario solicita” Se destaca en cursiva y en negrita que el proceso es repetitivo, por lo puede asociarse a un préstamo varias copias de materiales. Por otra parte, en cuanto a la excepción se tendría lo siguiente. En el paso 3, de comprobarse que el usuario ya tiene una copia del mismo material asignado en otro préstamo, no se incluye en el préstamo que está siendo procesado. Acá se varía la excepción: el caso de uso no termina, sino que puede seguirse con la solicitud de otros materiales para el préstamo. Podemos ver el diagrama resultante, como sigue.

173

Bibliotecario ingresa identificación del usuario

Comprobar la validez del usuario

[Sí] Leer código de barras del material

[No] Usuario Válido

Código leído

[No]

Ingresar código material con teclado

[Sí]

Comprobar material para préstamo

Usuario tiene otra copia prestada [No] [Sí] Usuario Acepta Condiciones

[No]

[Sí]

Continuar agregando

[Sí]

Agrega material a la solicitud

Figura 47. Continuación de la elaboración del diagrama de actividad para el caso de uso de Registrar Préstamo.

Con el fin de completar la visión que se da a partir de las modificaciones que realizamos en el paso 3 y su correspondiente excepción, hemos agregado también lo que se indica en el punto 4. Observe que, después de que se comprueba en la decisión llamada “Usuario tiene copia prestada”, en el caso de que sea positiva dicha comprobación, se pregunta si quiere continuar agregando materiales a la solicitud. Si se dice que sí, entonces se procede a leer el código de otra copia de un material.

174

En caso que la comprobación de que si una copia del material ya ha sido prestada al usuario resulta negativa, se sigue con los pasos que se dan en el paso 4: “El Sistema indica si el material puede ser prestado solo para uso interno de la biblioteca y el tiempo que puede ser prestado en cualquier caso”. Además, su correspondiente excepción indica que: “En el paso 4, luego de

indicarle al usuario las restricciones del préstamo, éste puede decidir no aceptar las condiciones, por lo cual el Bibliotecario termina la ejecución del caso de uso”.

Acá también nos encontraremos con que deben realizarse modificaciones (las cuales ya en el diagrama de la Figura 47 están materializadas). Un usuario podría no aceptar las condiciones del préstamo para un material en particular, pero sí para otros que le interesan. Por lo tanto, en el caso de la excepción, debería reescribirse así: “En el paso 4, luego de indicarle al usuario las

restricciones del préstamo, éste puede decidir no aceptar las condiciones, por lo cual el Bibliotecario prosigue con los otros materiales solicitados”.

Advierta, entonces, que en el diagrama anterior, se ejecuta una condición en la cual el Bibliotecario indica si el Usuario está de acuerdo (o no lo está) con las condiciones del préstamo. Si este indica que sí, se agrega la copia del material solicitado al trámite y, si la respuesta es negativa, se prosigue con la decisión de continuar agregando materiales en la solicitud de préstamo. Finalmente debe completarse el proceso, ejecutando el paso 5. Dicho paso debiera estar a continuación de la decisión de agregar (o no agregar) más materiales a la solicitud de préstamo. Por lo tanto, si se indica que no se agregarán más, entonces se da la actividad de registrar el préstamo. El diagrama completo de este caso de uso se vería así.

175

Bibliotecario ingresa identificación del usuario

Comprobar la validez del usuario

[Sí] Leer código de barras del material

[No] Usuario Válido

Código leído

[No]

Ingresar código material con teclado

[Sí]

Comprobar material para préstamo

Usuario tiene otra copia prestada [No] [Sí] Usuario Acepta Condiciones

[No]

[Sí]

Continuar agregando

[Sí]

Agrega material a la solicitud

[No]

Registrar Préstamo

Figura 48. Diagrama de actividad completo para el caso de uso de Registrar Préstamo.

Note que, una vez que se hace la actividad de Registrar Préstamo, se procede con la finalización del proceso. Finalmente, vea que un diagrama de actividad puede ayudarnos a documentar, de una forma conveniente y 176

relativamente sencilla, los casos de uso, considerando, además, lo pertinente a las condiciones (vistas como decisiones) y a los ciclos que pueden darse en el proceso.

Especificación de operaciones La capacidad de expresión de los diagramas de actividad también nos permite poder especificar lo que puede ocurrir en una operación particular de una clase. Por ejemplo, podemos servirnos de algunos de los diagramas de secuencia creados y, de esta forma, poder apoyar la especificación de algunas operaciones usando diagramas de actividad Analicemos la situación que puede derivarse del siguiente diagrama de secuencia. :RegistrarPréstamoInterfaz

:RegistrarPréstamoManejador

Bibliotecario IngresaIdentificaciónUsuario() ValidarUsuario()

IngresaMaterialPréstamo() TieneCopiaPrestada()

IncluyeMaterialPréstamo()

RegistraPréstamo() RegistraPréstamo()

Figura 49. Diagrama de secuencia de las clases de interfaz y gestión para el caso de uso de Registrar Préstamo.

Veamos que uno de los mensajes, vistos como operaciones, que van entre el actor Bibliotecario y el objeto de la clase RegistraPréstamoInterfaz es el que se llama IngresaMaterialPrestado (el segundo de arriba abajo). Tal como lo habíamos analizado, al visualizar la caja de activación, vemos cómo parten del objeto RegistraPréstamoInterfaz dos operaciones hacia RegistraPréstamoManejador:

177

TieneCopiaPrestada e IncluyeMaterialPréstamo. Esto significa que dentro de la operación IngresarMaterialPrestado, deben existir los llamados a esas dos operaciones. ¿Cuándo y cómo llamarlas? Eso puede especificarse mediante el diagrama de actividad. El diagrama de actividad podría ilustrar, visualmente, la siguiente lógica del algoritmo requerido en IngresarMaterialPrestado: “La operación tiene como

parámetro el código del material que quiere prestarse y la identificación del usuario que solicita. Debe comprobarse, mediante las operaciones del gestor, si tiene una copia prestada del mismo material y, de no ser así, puede incluirse en la solicitud del material para préstamo”. Por lo que ya sabemos de los

diagramas de actividad, podemos trazar el siguiente.

Declara variable comprobación = falso

comprobación = TieneCopiaPrestada

[falso]

IncluyeMaterialPréstamo

[verdadero]

mensaje = Ya tiene ese material asignado en otro préstamo

mensaje = Material incluido con éxito

Retorna mensaje

Figura 50. Diagrama de actividad para especificar la operación TieneCopiaPrestada.

178

Vea que al inicio se declara una variable booleana local llamada comprobación. Posteriormente comprobación asume el valor del resultado de la operación TieneCopiaPrestada. Si comprobación tiene valor verdadero (es decir, que el usuario sí tiene una copia del mismo material en préstamo actualmente), entonces una variable de tipo cadena de texto (o string) llamada mensaje, asume el valor de: “Ya tiene este material asignado en otro préstamo”. Si el valor es falso, se ejecuta la actividad con la operación IncluyeMaterialPréstamo. Posteriormente la variable mensaje asume el valor de: “Material incluido con éxito” Finalmente se ejecuta la actividad de retornar el valor de la variable y la operación termina. Tenga en cuenta que la especificación de operaciones debe valerse de muchas fuentes de información. Ya vimos que el diagrama de secuencia da una idea de qué operaciones deben ser llamadas por otra. Sin embargo, no se tiene una idea del flujo de control que debe darse en ellas, lo cual se complementa con un diagrama de actividad. Finalmente, un diagrama de clases nos debe asegurar algunas otras especificaciones, como por ejemplo, qué parámetros de entrada posee una operación y qué tipo de valor retorna. Juntando todos ellos, un programador puede tener la visión completa de lo que se requiere para la codificación de las operaciones lo cual, en el paradigma de orientación a objetos, es en sí misma, la codificación del sistema. DIAGRAMAS DE ESTADOS Otro diagrama importante para la especificación del software del sistema con que cuenta UML, es el llamado diagrama de estados. Un diagrama de estados puede documentar algunos estados importantes que poseen objetos del sistema y que resultan claves de visualizar y controlar (e igualmente, codificar y controlar en las operaciones). Por ejemplo, controlar el estado de un usuario ante el sistema podrá resguardar el hecho de que podamos prestarle material a un usuario solamente cuando esté libre de obligaciones con la Biblioteca. Otro ejemplo importante es el hecho de poder controlar el estado de una copia de material particular, de tal forma que no se representen inconsistencias en el sistema, como que se indique que una misma copia pueda estar prestada dos veces al mismo tiempo, o que no se indique que esté devuelta cuando sí lo esté.

Elementos de un diagrama de estados Los diagramas de estado son sencillos. Se componen de pocos símbolos a saber:

179

Símbolo

Estado

Nombre

Propósito

Estado inicial

Representa el estado inicial de un objeto

Estado

Representa un estado en particular en el que podría estar un objeto Representa la transición, por causa de eventos en el sistemas, entre dos estados de un objeto

Transición

Figura 51. Símbolos utilizados en los diagramas de estados.

Un ejemplo clásico para ilustrar un diagrama de estados, que tomamos de Larman (2003), puede verse alrededor de un teléfono. Cuando un teléfono está colgado, se encuentra en estado inactivo, mientras que al descolgarlo pasa a estado activo. Se identifican dos estados: activo e inactivo, a la vez que se dan dos eventos: colgar y descolgar el teléfono. Por lo tanto, un diagrama de estados para un objeto teléfono se vería así.

Inactivo

Activo [descolgar]

[colgar]

Note que en las transiciones entre estados, vistos como flechas, se visualizan cuáles eventos son los que desatan tales transiciones. En este caso, el evento descolgar hace que se de la transición del estado del teléfono de inactivo a activo y, en sentido contrario, el evento de colgar. Por lo tanto, lo anterior nos hace ver que para plantear un diagrama de estados debemos identificar: •

El objeto el cual va a ser descrito en sus posibles estados.



Los estados posibles en los que puede estar un objeto.



Los eventos del sistema que hacen que un objeto pueda cambiar de estado.



Las transiciones válidas entre estados.

Esto último es muy importante porque, de acuerdo con alguna condición del sistema, podrían existir transiciones entre estados que no sean válidas. Por ejemplo, en un objeto tipo Factura, si la factura ya ha sido confeccionada y pagada por parte de un cliente, esta asume un estado que se llama

180

“Cancelada”. Si se encuentra en ese estado, no podría entrar en un estado que no pudo haber estado antes, digamos “En confección” y, por lo mismo, que tenga efectos en el monto que ya ha sido cancelado: ¡sería el paraíso de alguien que le guste hacer fraude! Todo sistema podría tener restricciones de este tipo, donde haya transiciones que no puedan darse, o bien, que pudieran existir estados finales de los cuales no puedan salirse más7. Elaboración de diagramas de estados Podemos hacer, por lo tanto, un ejercicio con un objeto del tipo Copia, es decir, una copia de un material bibliográfico. Recordemos que esta clase tiene un atributo que se llama estado_copia, el cual, precisamente, busca reflejar el estado de un objeto de la Copia dentro del sistema. Usted recordará que, en el momento en que elaborábamos las clases conceptuales, buscábamos allí los posibles atributos de tales clases y, en particular para la clase Copia, indicábamos que el atributo estado_copia describía el estado de una copia de material en el sistema y que los posibles estados eran: Disponible, Prestada, En reparación o Anulada. Para el diagrama de estado de un objeto de tipo Copia, ya poseemos los dos primeros puntos: obviamente el objeto que va a ser descrito y los posibles estados. El diagrama preliminar lo veríamos de la siguiente forma:

Prestado

Disponible

En Reparación

Anulado

Vemos en este solamente los estados sin ninguna transición, las cuales procedemos a identificar a continuación. Para pensar qué transición puede darse a partir del estado inicial (la bolita rellena), debemos pensar solamente en uno de los estados que hay en el diagrama (desde el estado inicial puede irse solamente a uno de los estados). Podemos pensar que toda copia de material nuevo que se ingresa en el sistema, pasa inmediatamente a un estado 7

Para ello el estudiante se puede apoyar en la teoría que se desarrolla en las Matemáticas Discretas con relación a las “máquinas de estado finito” y la “teoría de autómatas”.

181

de “Disponible” y que, por lo tanto, es la transición que se da del estado inicial. No se visualiza que se ingresa una nueva copia y que directamente vaya a ser prestada, o entre en reparación o se anule. Para que alguna de estas últimas situaciones pueda darse, en primera instancia debe estar disponible. Por lo tanto, tenemos la primera transición que se da en nuestro diagrama.

Disponible

Nos detenemos en el estado Disponible y reflexionamos sobre cuáles transiciones son posibles. Para realizar este análisis, obviamente usted tendrá que conversar con los clientes y conocer mucho del contexto del problema que está tratando. Con el objeto del tipo Copia en estado Disponible, una copia bien puede pasar al estado de Prestada. Esta es una de las transiciones más obvias de nuestro sistema, pues es uno de los objetivos principales de la biblioteca y del software que la apoya. Ahora bien, pensemos que una copia estando Disponible, una vez devuelta por algún usuario, el bibliotecario puede verla y sentir que está descuadernada o con algún otro tipo de deterioro. Por lo tanto, del estado Disponible puede pasar al estado En Reparación. ¿Encontrándose en estado Disponible podría pasar directamente al estado Anulada? Entendemos por copia anulada el estado en que una copia no puede volver a estar disponible en el sistema, por algún deterioro irreversible o bien por pérdida o hurto. En este caso podemos pensar que, estando disponible e identificando un Bibliotecario algún deterioro, debe pasar previamente a un estado de En Reparación donde se valore y, si el daño es irreversible, la copia podría pasar a un estado de Anulada. En tal caso no puede irse directamente del estado de Disponible a Anulada. Ahora bien, podría en algún momento, realizarse un inventario en la biblioteca y detectarse que una copia fue robada de la colección, sin haber sido previamente prestada. Por lo tanto, se tiene que podría pasarse al estado de Anulada directamente desde estado de Disponible, por un evento así. En resumen, viendo el comportamiento de estados desde el estado de Disponible podemos ver las siguientes transiciones. Se presentan como una matriz, donde el contenido de las celdas corresponde al evento que dispara la transición y su correspondiente descripción. Las celdas que quedan en blanco

182

indican que no hay transiciones válidas entre los dos estados que hacen la intersección, por ejemplo entre el estado Inicio y En Reparación.

Estado Inicio

Disponible

Prestada En Reparación Anulada Ingresar: Se ingresa una nueva copia al Sistema y queda en estado disponible Prestar: Reparar: Reportar pérdida: Una copia se da en préstamo a Se envía la copia a Se anula del sistema una un Usuario de la Biblioteca reparar producto de la copia debido a que se ha detección de un deterioro detectado que esta se ha perdido

El diagrama resultante del análisis hecho hasta ahora correspondería con el siguiente.

[Reportar pérdida]

[Prestar]

Disponible

Prestado

[Reparar]

En Reparación

Anulado

Figura 52. Diagrama parcial de la transición de estados de la copia de un material bibliográfico.

Podemos continuar nuestro análisis desde los otros estados, de una forma semejante. Para ello completamos la matriz que comenzamos a realizar. En las intersecciones que quedan en blanco, se asume que no hay transiciones válidas. Esta matriz que presentamos a continuación, usted podrá analizarla y ver, de acuerdo con su criterio, su validez.

183

Estado Inicio

Disponible Ingresar: Se ingresa una nueva copia al sistema y queda en estado disponible

Disponible

Prestada

Prestada

Prestar: Una copia se da en préstamo a un Usuario de la Biblioteca Devolver: Se registra la devolución de la copia

En Disponer: Reparación La reparación ha sido concluida por lo cual la copia vuelve a estar disponible

En Reparación

Reparar: Se envía la copia a reparar producto de la detección de un deterioro

Anulada

Reportar pérdida: Se anula del Sistema una copia debido a que se ha detectado que esta se ha perdido

Reportar pérdida: El Usuario indica que se ha perdido la copia que le había sido prestada Anular por no localización: No se localiza un usuario al que se le había prestado la copia, por lo cual después de cierto tiempo se anula del sistema Anular por daño: Mantener: El daño detectado es irreparable por Se mantiene en reparación al finalizarse lo cual se anula. un trabajo indicando que debe hacerse otro tipo de trabajo, o bien rehacer el que se ha hecho.

Anulada

De la matriz note lo siguiente: en primer lugar, el estado de Anulada es un estado final. De él no puede salirse. No hay transiciones válidas desde dicho estado8. En segundo lugar fíjese que las transiciones entre mismos estados son válidas, como sucede con En reparación. Allí, como se indica, puede una copia permanecer en ese estado, luego de finalizar un proceso parcial o mal hecho de reparación. El diagrama final para el objeto copia se vería a continuación:

8

De alguna forma, todo sistema deberá permitir salir de cualquier estado por algún error que se cometa, pero tal acción debe estar muy controlada requiriendo de autorizaciones muy precisas.

184

[Devolver] [Reportar pérdida]

[Prestar]

Disponible [Reparar]

Prestado

[Anular por no localizar] [Mantener]

En Reparación

Anulado

[Disponer] [Anular por daño]

Figura 53. Diagrama de estado completo para la copia de un material bibliográfico.

Finalmente vea que, mediante los diagramas de estados, pueden documentarse y visualizarse aspectos claves de control del sistema. Los eventos que se dan en las transiciones podrían corresponder a operaciones, o bien ser base para que dentro de ellas pueda haber estructuras de control que garanticen que se están dando las transiciones permitidas. Tales estructuras de control pueden ser vistas dentro de un diagrama de actividad. Es ideal entonces que, tanto para el desarrollo, como las pruebas que deben realizarse en el software desarrollado, que pueda contarse con diagramas de este tipo para poder garantizar la buena construcción del software, validando aspectos sumamente importantes como los estados en los que puede estar un objeto.

185

EJERCICIOS DE AUTOEVALUACIÓN 1. Elabore los diagramas de secuencia para el Sistema de Reserva de Espectáculos en línea que ilustre lo siguiente. -

-

La interacción del actor del sistema que quiera realizar la reservación con el sistema. Deduzca del punto anterior la clase de diseño de la capa de interfaz para el caso de uso involucrado. La interacción entre los objetos entre la capa de interfaz y la capa de gestión del caso de uso involucrado.

Note que debe elaborar las clases de diseño y de gestión correspondientes. 2. Realice el diagrama de secuencia que permita visualizar la reserva de un espectáculo involucrando las capas de interfaz, de gestión, de negocio, de sistema y de base de datos. Siga la elaboración hecha para deducir la Figura 40. 3. Explique por qué son importantes los casos de uso para la elaboración de los diagramas de secuencia y cómo repercuten en la elaboración de las clases de diseño. 4. Explique cómo se diferencian y cómo se complementan los diagramas de secuencia y de actividad en la documentación de los casos de uso. 5. Represente, mediante un diagrama de actividad, el algoritmo de la sumatoria infinita, desde n = 0, de la fracción 1/rn, mientras que el término de la fracción sea superior a 0,00001. 6. Escoja dos operaciones de la clase de gestión elaborada en el ejercicio 1 y especifíquelas mediante diagramas de actividad. 7. Tome el concepto de Reservación en el Sistema de Reservaciones de Espectáculos en Línea, de tal forma que pueda: -

Identificar los estados de una Reservación. Identificar las transiciones válidas entre estados para una Reservación representándolas mediante un diagrama de estados.

186

CAPÍTULO

5

DE CARA A LA IMPLEMENTACIÓN

SUMARIO

CONSIDERACIONES PRELIMINARES LAS PRUEBAS EN LA INGENIERÍA DE SOFTWARE De lo integral a lo particular a lo integral Pruebas de unidad Pruebas de integración y componentes DESPLEGABDO LA SOLUCIÓN Elementos de un diagrama de despliegue Construyendo un diagrama de despliegue COMPLETANDO EL PROCESO DE TRANSICIÓN CONCLUSIONES

187

OBJETIVOS Una vez que usted estudie este capítulo, podrá llevar a cabo cada una de las siguientes actividades de aprendizaje, que le servirán para comprobar cuánto ha aprendido de este tema. -

Justificar la utilidad de los modelos creados para apoyar los distintos niveles de prueba de software.

-

Justificar la utilidad de los casos de uso en la prueba de los elementos de software de forma particular e integral.

-

Manejar los principios básicos del uso de componentes como forma de integración modular y arquitectónico del desarrollo de software.

-

Crear diagramas de despliegue con el fin de definir los elementos de hardware que sustentan la solución de software.

-

Establecer claramente la relación de un desarrollo usando el Proceso Unificado y el UML con los distintos elementos que conforman un Sistema Basado en Computadoras.

188

CONSIDERACIONES PRELIMINARES Los temas que hemos abordado en el libro, hasta ahora, buscan dotarlo de técnicas para que usted desarrolle las tareas de Ingeniería de Software usando los principios del Proceso Unificado, los cuales explotan las capacidades del Análisis y Diseño Orientado a Objetos y los diagramas de UML. Como tal, usted ha podido constatar, en la experiencia del ejercicio de la construcción del software para el Sistema de Préstamos Bibliotecarios, que buscamos avanzar en las tareas de Análisis y de Diseño, usando convenientemente ciertos diagramas. Estos diagramas no son exclusivos de una fase u otra. Por ejemplo, pueden usarse diagramas de clases en el Análisis o en el Diseño. O, por otra parte, los diagramas de secuencia pueden usarse para documentar casos de uso (fase de Análisis) o definir clases de diseño de gestores (fase de Diseño). Basados en el mismo principio iterativo del Proceso Unificado, podemos enfrentarnos también con el hecho de que se estén realizando tareas de Diseño y debamos enfrentarnos, en algún momento de ese proceso, a decisiones de Análisis. Esta característica en la construcción del producto no es un descubrimiento por sí mismo del Proceso Unificado; es algo que comúnmente pasa y que esta forma de desarrollar software facilita integrarlo dentro de la metodología de desarrollo, sin tener que “echar al cesto de la basura” lo realizado hasta ese momento. Muchas veces se trata, simplemente de modificar un diagrama. ¡Qué cómodo, comparado a mis años de hacer diagramas de flujo de datos con monedas! Por otra parte ha notado cómo los casos de uso son algo omnipresente en todo el desarrollo. Todos los diagramas y modelos que hemos producido han estado guiados por los casos de uso. No gratuitamente; se dice que el Proceso Unificado está guiado por los casos de uso. Este último capítulo lo relacionaremos con los procesos de pruebas e implementación del producto, lo cual se denomina la fase de Transición en el Proceso Unificado. Nos valdremos, nuevamente, de los casos de uso y otros diagramas, como los llamados diagramas de despliegue, para definir aspectos relacionados con la estrategia de implementación del sistema. Dicha estrategia está muy relacionada con la arquitectura del sistema y los temas que hemos visto, previamente, como la arquitectura en n-capas. De paso, estaremos tocando aspectos introductorios relativos a los componentes en el software y cómo estos se resuelven y son importantes en el marco del Proceso Unificado con UML.

189

LAS PRUEBAS EN LA INGENIERÍA DE SOFTWARE No es el objetivo ahondar en este tema que usted debe manejar, producto de sus estudios previos en otros cursos de Ingeniería de Software. Basta que repasemos algunos aspectos básicos relacionados con las pruebas de un producto de software. Las pruebas son un proceso cuyo objetivo es detectar errores en el software construido. Cada una de las fases del Proceso Unificado, el Inicio, la Elaboración, la Construcción y la Transición, están sujetas de realizárseles pruebas. En particular, durante la Transición se hacen las pruebas necesarias para poder entregar un producto de software que responda a todos los objetivos para que el que fuera creado, esto es, que cubra todos los casos de uso. Se establece una versión beta, la cual puede ser examinada por un grupo de usuarios y evolucionar hacia la versión final del software requerido. En este momento, es conveniente recordar la Figura 5 vista en este material:

Actividades fundamentales Requisitos

Fases Inicio

Elaboración

Construcción

Transición

...

… …

Iter Iter #n - 1 # n

Análisis

Diseño

Implementación

Pruebas

Iter #1

Iter #2



Figura 54. Las pruebas están en todas las fases del Proceso Unificado, pero aumentan en la fase de Transición.

190

La producción de esta versión beta implica que ya se ha superado, dentro de la fase de Construcción del Proceso Unificado, la etapa de Codificación o Programación. La discusión sobre técnicas programación sobrepasa los alcances de este libro, dado que usted, en este punto del avance de sus estudios, debió ya superar los cursos básicos, intermedios y avanzados de programación. De igual forma, la teoría de programación debió ya incluir lo referente a las técnicas de pruebas. No obstante lo anterior, podemos resaltar algunas facilidades que da el Proceso Unificado, utilizando UML, para poder apoyar el plan de pruebas. Las pruebas, en general, pueden dividirse en estas fases: Pruebas de unidad

Se prueba cada una de las piezas de software (clases, componentes) que se han de forma individual.

Pruebas de integración

Las piezas de software se prueban en su interacción con otras

Pruebas de sistema

Se prueba el software en relación con otros elementos del sistema (hardware, redes, bases de datos, gente) y de acuerdo con los objetivos planteados.

Tabla Nº 9. Clasificación general de los tipos de pruebas en la Ingeniería de Software

Viendo esta clasificación, debemos tener en cuenta un aspecto importante que busca garantizar un el Análisis y Diseño Orientado a Objetos que se obtiene mediante el Proceso Unificado: cualquier concepto que se ha trabajado debe provenir de un objetivo “real”, identificado desde el momento en que se desarrollaron los casos de uso. Esto, ni más ni menos, debió seguir una validación constante del cliente o usuario del sistema. Hemos ya mencionado que las tareas de prueba están presentes en todas las fases del Proceso (ver Figura 54). Por ello cada iteración que se realiza en el proyecto debe estar sujeta de un examen, en el cual el cliente debe jugar un papel relevante. Idealmente, por lo tanto, la mínima pieza de software debería estar generada en función del problema real. Al tratar de reducir el riesgo de malinterpretaciones, el Proceso Unificado trata de garantizar que no “haya pérdida” en el desarrollo del proyecto, detectando lo antes posible las fallas. Ahora bien, independientemente de cuándo suceda en el tiempo del proyecto, las pruebas, tal como las clasificamos en la Tabla Nº 9, deben darse con la estrategia descrita allí. ¿Cómo pueden los modelos generados a lo largo del proyecto apoyar la estrategia de pruebas?

191

De lo integral a lo particular a lo integral Es bueno, a esta altura de nuestro estudio, tratar de recordar de lo que se trata un caso de uso: a grandes rasgos, un caso de uso es un objetivo que tiene que cumplir el sistema. La forma en que planteamos los casos de uso no nos indica nada en particular referente a las piezas de software que intervienen en este. Hemos visto cómo un caso de uso debe ser, por ejemplo, comprendido fácilmente por personal que no es especialista en software. Además, también hemos estudiado cómo, para poder cumplir el objetivo del caso de uso, colaboran múltiples objetos derivados de las diferentes clases que participan en la solución. ¿Qué puede significar ello para las pruebas de software? Piénselo por un instante, de acuerdo con lo descrito en la Tabla Nº 9 y lo retomaremos más adelante. Cuando buscamos sustentar los casos de uso en el sistema, creamos modelos de clases, los cuales, a su vez, proveerán los objetos que intervendrán para poder cumplir el objetivo del sistema señalado en el caso de uso. Por ejemplo, en el caso del Sistema de Préstamo Bibliotecario que hemos seguido, el caso de uso de Registrar Préstamo tiene varias condiciones que deben cumplirse. Esto lo podemos ver en el escenario de este caso de uso, el cual puede resumirse en: a) b) c) d) e)

El Usuario debe estar inscrito en la Biblioteca. El Usuario no debe tener deudas con la Biblioteca. No debe tener prestada otra Copia del Material. Debe asignarse un tipo y tiempo de préstamo. La Copia del libro debe quedar en estado de prestada y asignada al Usuario.

En todos pasos intervienen muchos objetos de distintas clases. Por lo tanto, en un plan de pruebas, el cumplimiento de un caso de uso nos indicará que estamos ante pruebas de integración. Pero debe notar que el caso de uso es un insumo esencial que, si está bien planteado, desarrollado y especificado, es un insumo que facilita nuestro plan de pruebas. Por lo tanto: ¡no descuide el celo con que debe desarrollar los casos de uso! Si usted se fija en los diagramas de actividad creados, por ejemplo, el de la Figura 48, encontrará un “plano” para poder realizar la prueba del caso de uso. En sí, muchos de los elementos que integran el diagrama de actividad pueden relacionarse con un método u operación de una clase. En la siguiente figura asociaremos, en letras rojas, la operación que puede ayudar a implementar el caso de uso. El formato que usaremos será: Nombre de la operación:Clase a la que pertenece. Por ejemplo, es el caso de ObtieneEstado:Usuario.

192

Bibliotecario ingresa identificación del usuario

Comprobar la validez del usuario

ObtieneEstado:Usuario [Si] Leer código de barras del material

[No] Usuario Válido

Código leído

[No]

Ingresar código material con teclado

[Sí]

Comprobar material para préstamo

TieneCopiaPrestada:DetallePréstamo Usuario tiene otra copia prestada [No] [Sí] Usuario Acepta Condiciones

[No]

[Sí]

Continuar agregando

[Sí]

Agrega material a la solicitud

IncluirCopiaEnPréstamo: Préstamo [No]

Registrar Préstamo

RegistrarPréstamo: Préstamo

Figura 55. Operaciones involucradas en el caso de uso de Registrar Préstamo.

193

De forma complementaria, los diagramas de secuencia también deben darnos la capacidad de poder visualizar todas las operaciones que intervienen (y que debemos probar) para poder realizar un caso de uso. En ello, podemos completar la de un diagrama de actividad, dado que el diagrama de secuencia define todas las operaciones que intervienen en todas las capas (ver el ejemplo de la Figura 40 para Registrar Préstamo). En tal caso, al probar el caso de uso, debe probarse también la correctitud con que funcionan dichas operaciones. Como tales, estas últimas pertenecen a una clase. Por lo tanto, usted está enfrentando aspectos relacionados con la particularidad de las unidades de software más elementales que tenemos en nuestra solución: las clases. Los casos de uso llevan intrínseco las pruebas de unidad. De hecho, el análisis de lo que cada clase debe proveer a través de sus operaciones, nace del análisis de los casos de uso y, para poder cumplir los objetivos de éstos, el modelo de diseño añade otros más (constructores, operaciones de “obtener/establecer”, entre otros). Todo este proceso complejo de construcción, lo hemos seguido en el caso del Sistema de Préstamo Bibliotecario. Al realizar la prueba de todos los casos de uso de un sistema, deberíamos probar todas las operaciones de todas las clases que intervienen. En sí, también nos enfrentamos a lo particular. Los casos de uso, en sí, nos ayudan en lo integral y en lo particular de las pruebas. Claro está, que las pruebas de unidad deben hacerse también tomando cada clase separadamente y, en cada una de las operaciones, realizar las pruebas conforme a los objetivos de ellas. Hacemos una pequeña reflexión en el siguiente apartado. Pruebas de unidad Recordemos que uno de los objetivos más importantes de la Ingeniería del Diseño (entre muchos otros), es el llamado Diseño Procedimental. Este lo podemos entender como la definición algorítmica de los procedimientos, funciones, operaciones o métodos (dependiendo del paradigma de desarrollo que estemos usando), que se hayan identificado. A partir de ello, podemos considerar varios aspectos con respecto a los modelos que generamos usando UML. En primer lugar, a lo largo del proceso que se ha ejemplificado en este libro, el Sistema de Préstamos Bibliotecarios, se han generado modelos como el Modelo Conceptual del Clases y el Modelo de Clases de Diseño. Un hito importante es poder identificar, en las clases de diseño, todas las operaciones que una clase debe tener para cumplir su propósito dentro del sistema.

194

Algunas de ellas las definimos en el Modelo Conceptual y otras fueron añadidas y especificadas en el Modelo de Diseño. Una operación existe en una clase con el propósito de que de los objetos derivados de dicha clases puedan cumplir con las tareas que se esperan de estos dentro del sistema. Por ejemplo, la clase Préstamo tendrá las operaciones necesarias para que los objetos creados cumplan su rol. Así también lo podemos afirmar para clases de diseño (por ejemplo, de las capas de interfaz, de gestión, de sistema). Vimos que, referente a la especificación de operaciones, podíamos recurrir a modelos como los Diagramas de Actividad para realizar dicha especificación (vea el ejemplo de la Figura 48 para la operación TienaCopiaPrestada). Con estos diagramas, de forma relativamente sencilla, puede detallarse el algoritmo requerido de una operación. Además, de sus cursos de programación podrá recordar que al crear una operación, debe completarse una especificación, la cual puede incluir: ƒ

Nombre de la operación.

ƒ

Clase a la que pertenece.

ƒ

Tipo de retorno de la operación (por ejemplo si devuelve un valor entero, un booleano, una cadena de caracteres, entre muchos tipos, o bien ningún tipo – en cuyo caso en JAVA se dice que es de tipo void).

ƒ

Rango de valores válidos de retorno.

ƒ

Parámetros que recibe y los valores permitidos en cada caso.

ƒ

Resultado esperado de la operación: por ejemplo, si cambia el estado de algún elemento del sistema (digamos que un material bibliográfico pasa de estar en estado Prestado a un estado Disponible).

ƒ

Especificación algorítmica: diagrama de actividad para la operación.

Para el caso de TieneCopiaPrestada, podemos darnos el ejemplo siguiente:

195

Nombre Clase Tipo de retorno Rango de valores de retorno Parámetros

TieneCopiaPrestada RegistraPréstamoManejador String pUsuario: instancia de un usuario de la biblioteca pCopia: instancia de la copia de un material bibliográfico en la biblioteca

Resultado

Devuelve el mensaje “Ya tiene ese material asignado en otro préstamo”si el usuario indicado en pUsuario ya tiene asociado un préstamo de otra copia del mismo material asociado a pCopia. De lo contrario, devuelve el mensaje “Material incluido con éxito”.

Especificación algorítmica

Declara variable comprobación = falso

comprobación = TieneCopiaPrestada

[falso]

IncluyeMaterialPréstamo

[verdadero]

mensaje = Ya tiene ese material asignado en otro préstamo

mensaje = Material incluido con éxito

Retorna mensaje

Figura 56. Especificación de la operación TieneCopiaPrestada.

Esto último, en conjunto con los modelos creados en UML, nos sirve de insumo para las pruebas de unidad. 196

Como ya mencionamos, no pretendemos ahondar en teoría que usted ya maneja de sus cursos previos de programación. No obstante, puede apreciar cuánto facilita un Análisis y Diseño Orientado a Objetos usando UML, el plan de pruebas que debe ejecutarse. En ello es esencial que usted desarrolle bien los casos de uso. La visión integral que éstos proveen, “amarran” muy bien los elementos particulares de software que se han creado. No olvide, además, que las pruebas en el Proceso Unificado no son algo exclusivo del final del proyecto relacionado, solamente, con el código creado: todos los modelos son sujetos de examen. Esto ha sido cierto en el proceso que hemos desarrollado a lo largo de este texto. Por ejemplo, se comprobó en muchos momentos y en fases distintas (de análisis, de diseño), lo correcto (o incorrecto) de los modelos creados. En muchos casos corregimos lo que veníamos trabajando, añadiendo o modificando clases o parte sustantivas de éstas. Al final, tales exámenes son ganancia para el proceso de programación y para el proceso de pruebas, dado que entre más depurado esté el modelo de clases resultante (en cada una de las capas de la arquitectura de n-capas), será más preciso el código de programación que se genera. Recuérdese que uno de los progresos que ha conllevado el UML, es que muchas herramientas de software han podido suministrarnos una correspondencia muy alta entre el modelo y un lenguaje de programación orientado a objetos. Pruebas de integración y componentes Hemos mencionado que una forma conveniente que nos proporcionan los casos de uso, es que se especifica cómo deben coordinarse los objetos de distintas clases para poder cumplir los propósitos de dicho caso de uso. Cuando probamos la ejecución de un caso de uso, estamos realizando pruebas de integración. En la Ingeniería del Diseño (independientemente de la metodología que usemos), encontramos también aspectos relacionados con la teoría de la modularidad, la cual sustenta la creación de componentes. De acuerdo con la OMG (Object Management Group), un componente es una parte modular,

desplegable y reemplazable de un sistema que encapsula implementación y expone una serie de interfaces.

La definición anterior puede recordarnos la definición de objetos y clases en el Paradigma de Orientación a Objetos. Precisamente, uno de los aspectos más importantes de este paradigma, es que sus piezas de software más elementales (los objetos derivados de las clases), cumplen muchos principios de la modularidad requerida por los principios de diseño de software.

197

Ahora bien, un componente es más complejo que una clase y, de hecho, puede agrupar muchas clases. Los componentes se asocian con el concepto de módulo, es decir, unidades de software que tienen alta cohesión y bajo acoplamiento. Por alta cohesión diremos que el módulo cumple con un conjunto de responsabilidades enfocado. Por ejemplo, si tenemos un módulo para la tramitación de préstamos y devoluciones de libros en una biblioteca, tal módulo cumplirá esas dos responsabilidades y sabemos que tenemos que acudir a dicho módulo para ello. En cuanto al bajo acoplamiento, al existir la necesidad de colaborar entre módulos, este debe ser mínimo. Cada componente de software debe presentar una o varias interfaces. A través de estas interfaces se accede a los servicios que provee el módulo. En el Paradigma de Orientación a Objetos, usted recordará que una interfaz es algo parecido a una clase, con la peculiaridad de que solamente define la signatura (o definición) de operaciones. Para cada interfaz, deberá existir una o varias clases que implementen TODAS las operaciones allí definidas. Por ejemplo, se puede definir una interfaz el proceso de registrar un préstamo en el Sistema Bibliotecario de Préstamo, concebida mediante estas operaciones: IRegistrarPréstamo + IngresarIdentificaciónUsuario () : String : String + IngresarMaterialPréstamo () : int + RegistrarPréstamo ()

Figura 57. Interfaz para Registrar Préstamo.

Note que al lado superior izquierdo hay un símbolo de un círculo asociado con una línea, lo cual comúnmente, valga la redundancia, simboliza a las interfaces. También es común encontrar la convención de que toda interfaz inicie su nombre con la letra “I” mayúscula. El código en JAVA de una interfaz es sencillo. Este se visualiza así: public interface IRegistrarPréstamo { public abstract String IngresarIdentificaciónUsuario(); public abstract String IngresarMaterialPréstamo(); public abstract int RegistrarPréstamo(); } Figura 58. Código en JAVA para la interfaz IRegistrarPréstamo.

198

Posteriormente podemos indicar cuál clase es la encargada de implementar esta interfaz. En este caso podremos considerar que el la clase de diseño de gestión RegistrarPréstamoInterfaz, sea la encargada de implementar la interfaz IRegistrarPréstamo9. public class RegistrarPréstamoInterfaz implements IRegistrarPréstamo { public RegistrarPréstamoManejador gestor; public RegistrarPréstamoInterfaz(RegistrarPréstamoManejador gestor) { // TODO: implement } public String IngresaIdentificacionUsuario(java.lang.String pIdUsu) { // TODO: implement return null; } public String IngresaMaterialPréstamo(java.lang.String pIdCopia, int pTipo) { this.gestor.TieneMaterialPrestado(idCopia); this.gestor.IncluyeMaterialPréstamo(idCopia); return mensaje; } public int RegistraPréstamo(java.lang.String pIdBiblio, java.lang.String[] pCopias) { // TODO: implement return 0; }

pIdUsu,

java.lang.String

} Figura 59. Código en JAVA de clase RegistrarPréstamoInterfaz que implementa la

interfaz IRegistrarPréstamo.

Se resalta en letra negrita la palabra clave implements seguida del nombre de la interfaz IRegistrarPréstamo. De esta forma, en JAVA la interfaz en cuestión tiene una implementación en esta clase. 9

En el ejemplo que estamos desarrollando se está eligiendo el gestor de la capa de interfaz como la clase que implementa una interface de JAVA. No debe confundirse la capa de interfaz con una interface. Las interfaces pueden implementarse con clases de cualquier capa.

199

Imagine, por otra parte, que se modifica todo el modelo de clases en n-capas que hemos realizado hasta ahora, de tal forma que también se tenga la capacidad de administrar las devoluciones de los materiales prestados. De igual forma puede tenerse otra interfaz llamada IRegistrarDevolución, asociada con un gestor de la capa de interfaz para el manejo de este caso de uso. En sí, entonces, estaríamos en capacidad de crear un componente de software que tuviera esas dos interfaces, que podría llamarse AdministrarPréstamo. El componente, en UML, se visualiza, tal como se ejemplifica en la Figura 60, como una pieza rectangular, con dos conectores a mano izquierda: AdministrarPréstamo

Figura 60. Componente AdministrarPréstamo en el Sistema Préstamos Bibliotecarios.

En PowerDesigner podemos asociar las interfaces de este componente en la definición misma de éste, tal como se muestra en la siguiente figura.

Figura 61. Asociación de interfaces para un componente en Power Designer.

200

Dentro de un componente no solamente definimos la interfaz, sino también toda la implementación necesaria. Por lo tanto, deben incluirse las clases que proporcionan la implementación de estas responsabilidades asignadas al componente. En el caso de Power Designer también podemos realizarlo, tal como se muestra en la Figura 62.

Figura 62. Asociación de interfaces para un componente en Power Designer.

Estudiar a profundidad el tema de construcción de componentes escapa a los alcances de este libro, dado que los temas avanzados en ellos son complejos cuando se abarcan tecnologías como los componentes Enterprise Java Beams (EJB) o los COM. No obstante de esta reflexión que estamos haciendo, podemos hacernos algunos cuestionamientos. Observe que en la lista de clases escogidas, estamos incluyendo clases como Usuario o Bibliotecario. Lo anterior debería hacernos pensar en el grado de cohesión y acoplamiento que tiene el módulo. Al esbozar que las responsabilidades de nuestro componente son las de registrar préstamos y devoluciones de materiales bibliográficos, ciertamente que para ello necesitamos información del Usuario y del Bibliotecario.

201

Sin embargo, al contener en el componente las clases involucradas, también estaríamos asumiendo que la responsabilidad del componente tendría que ir en la administración de la información de los usuarios y de los bibliotecarios, por lo cual deberían tomarse algunos de los siguientes cursos de acción. Agregar otras interfaces para manejo de esa información. Quitar las clases de Usuario y Bibliotecario de la definición del componente y crear componentes especializados para la administración de éstos. ¿Qué curso de acción sería mejor tomar? Examinándolo bajo la teoría de la modularidad, con respecto a los principios de cohesión y acoplamiento, nótese que se está bajando la cohesión (puesto que se está aumentando la responsabilidad del módulo). Lo anterior porque, ya no solo se encargaría de administrar préstamos y devoluciones del Material Bibliográfico, sino que estaría administrando la información del Usuario y del Bibliotecario. Como consecuencia de lo anterior, se aumenta el acoplamiento y, por tanto, para cumplir las responsabilidades del módulo, debe conocerse lo correspondiente a la definición de los conceptos de Usuario y Bibliotecario, lo cual, al fin y al cabo lo puede suministrar una operación proveniente de componentes especializados en ellos. Dentro de los principios de arquitectura del Proceso Unificado, por otra parte, se busca crear una arquitectura de piezas de software (componentes) que sea altamente reutilizable. En este caso, debemos asegurarnos que si se hacen modificaciones en el software, estas no afecten lo que no debe afectarse. Por ejemplo, si modificamos algo relativo a la administración de usuarios de la biblioteca, tenemos que afectar el componente relacionado con la administración de devoluciones y préstamos, lo cual es indeseable. O si por otra parte, queremos reutilizar la administración de usuario creada para este sistema en otro sistema, deberíamos llevar también todo lo relacionado con devoluciones y préstamos de libros, lo cual no tendría nada que ver en la otra solución. Por lo tanto, se elegiría el curso de acción b). La definición de clases para el módulo quedaría así.

202

Figura 63. Clases resultantes del componente de AdministrarPréstamo.

Un diagrama de componentes podría ilustrar el acoplamiento entre estos, de la siguiente forma: AdministrarPréstamo

Usuarios

Figura 64. El componente AdministrarPréstamo se acopla con el componente Usuarios.

Dicho acoplamiento podría hacerse mediante una operación que retorne un objeto de tipo Usuario, que es el que necesita AdministrarPréstamo para cumplir sus responsabilidades. ¿Por qué tocamos el tema de los componentes en este punto? Por muchos motivos. En primera instancia note que pueden existir muchos niveles de integración en el software que deben probarse.

203

Cuando creamos un componente, la implementación de este puede llevar la coordinación de muchos objetos provenientes de muchas clases. Fíjese, por ejemplo, en la complejidad que se expone en la Figura 40 de este libro, para el caso de registrar un préstamo en la Biblioteca. Esta integración debe verificarse a lo interno del componente, pero, a su vez, debe probarse cómo interactúa este componente con los otros para también cumplir la solución deseada. Por lo tanto, las pruebas de integración pueden verse a nivel de colaboración de objetos dentro de un componente y también a nivel de acoplamiento entre componentes. Idealmente, de acuerdo con el desarrollo orientado a componentes, deberían construirse estas piezas de software de tal forma que puedan reutilizarse posteriormente. Estas ya han sido probadas y para integrarlas a otras soluciones, se tiene certeza de que cumple con lo que sus interfaces definen. De esta forma, ya no serían las clases, sino los componentes las unidades más elementales en este tipo de desarrollo de software10. Por otra parte, y complementando el párrafo anterior, el Proceso Unificado, a la vez que es guiado por casos de uso, también se orienta a la arquitectura. El desarrollo de componentes tiene, en cuanto al software, ese objetivo de crear piezas que sean reutilizables, intercambiables y fácilmente mantenibles. Por ejemplo, si se cambia la administración de usuarios en la Biblioteca y se sigue respetando la interfaz requerida por la administración de préstamos en el Sistema, entonces el impacto de ello fue mínimo en el funcionamiento global del sistema. Siguiendo con el ejemplo, si se detecta que debe realizarse una modificación en el componente de usuarios pero que no afecta la administración de préstamos, entonces el Sistema de Préstamos Bibliotecarios sigue funcionando. Por último, desde un punto de vista muy práctico, el componente va a corresponder, en lenguaje máquina, a un archivo DLL o EXE. Los efectos prácticos de conseguir modularidad redundan en que el archivo generado por el proceso de compilación, nos dará todos los servicios que requerimos en la conformación de la solución. De esta forma, si bien puede profundizarse mucho más en este tema, usted ya tendrá una idea completa de los propósitos del Proceso Unificado. Finalmente, un diagrama de componentes que puede proponeser para nuestro sistema, sería el que sigue.

10

Ver capítulo 30 de Pressman (2005)

204

Bibliotecario

AdministrarPréstamo

MaterialBibliográfico

Financiero

Usuarios

Figura 65. Diagrama de componentes que implementan el Sistema de Préstamo

Bibliotecario.

En la Figura 65 note que podríamos estar ante componentes complejos en su implementación, con muchas interfaces, como podría ser el componente de un Sistema Financiero. No obstante, se rescata el hecho de que para el Sistema de Préstamo Bibliotecario, no tenemos que inventar la rueda a cada rato. Si la organización ya tiene un Sistema Financiero y, de este necesitamos su servicio de “generar una cuenta por cobrar”, entonces simplemente utilizamos lo ya creado. De igual forma, podemos discutir si el componente de Bibliotecario corresponderá más bien a usar un componente del sistema de Recursos Humanos, donde existirá un funcionario descrito en el manual de puestos con esta categoría. En cuanto al componente de Material Bibliográfico, sabemos también su complejidad, dado que tiene intrínseco estructura de herencia que maneja cualquier tipo de material que puede prestarse (libros, revistas, vídeos, tesis), además de las copias de cada uno de estos tipos de material. ¿Qué requeriría el componente de AdministrarPréstamo del componente de MaterialBibliográfico? Le dejamos que, como ejercicio, usted responda a esta pregunta. Esta visión de componentes, cuanto mayor se apropie usted como ingeniero de ella, facilita una de las primeras tareas que deben definirse en la fase de inicio del Proceso Unificado: la especificación de los principales subsistemas. Ante las necesidades que pueden esbozarse allí, si la organización fomenta la creación de componentes, usted podrá decir muy tranquila y felizmente, por ejemplo: “del problema de crear cuentas por cobrar por morosidad no me preocupo, porque ya eso lo proporciona el componente del sistema financiero. Me concentraré en crear este subsistema con estos componentes”.

205

DESPLEGANDO LA SOLUCIÓN La Ingeniería de Sistemas no abarca solamente el software. Nos hemos enfocado, durante el desarrollo de este material, en el tema de la Ingeniería de Software en el proceso de ir solucionando uno de los aspectos más críticos e inciertos en los sistemas basados en computadoras. Sin embargo, el software que se desarrolla y pasa sus pruebas, debe integrarse con los otros elementos que integran la solución. De acuerdo con Pressman (2005), los elementos de un sistema basado en computadora se constituyen en: hardware, software, base de datos, documentación, gente y procedimientos. El ingeniero de sistemas debe construir una solución dando una definición y solución para cada uno de estos elementos. Note que el desarrollo que se hace usando el Proceso Unificado mediante UML, ayuda dar soluciones en la Ingeniería de Sistemas. Elemento del sistema basado en computadora Hardware Software Bases de datos Gente Documentación

Procedimientos

Desarrollo usando UP y UML Utilización de los diagramas de despliegue para definir los equipos de hardware que se usarán en la solución. Definición de los modelos de análisis y diseño para la codificación de la solución Definición de las necesidades de persistencia de los objetos en una base de datos. Diagramas de despliegue. Definición de los actores humanos en la interacción con el software. Documentación técnica y del ámbito del negocio (incluyendo los modelos creados en UML y los casos de uso, respectivamente). Muchas herramientas proveen la facilidad de generar automáticamente, documentación técnica relacionada con los modelos creados. Los casos de uso pueden documentar aspectos de los procedimientos existentes en el negocio (o los nuevos que modifican los actuales a partir de la creación del sistema desarrollado)

Tabla Nº 10. Ejemplos de cómo aporta el UP usando UML en la Ingeniería de Sistemas.

Tal como se menciona en la tabla anterior para el caso de la Documentación, hay herramientas que manejan el UML que facilitan el proceso de generación de documentación técnica.

206

Por ejemplo, en el caso de la herramienta Power Designer, puede crearse un documento a partir de los modelos creados. Vemos en la siguiente figura el ambiente de desarrollo de la documentación en esta herramienta.

Figura 66. Ambiente para creación automática de la documentación técnica del sistema en Power Designer.

En la Figura 66 podemos notar las facilidades que proporcionan las herramientas hoy en día para el proceso de desarrollo y documentación. Un documento se genera a partir de la estructura que el Ingeniero determine. Un término nuevo que se aprecia en la Tabla Nº 9, es con respecto a los llamados Diagramas de despliegue. Este tipo de diagramas, perteneciente también a la amplia familia de diagramas de UML, viene a apoyar la labor de la Ingeniería de Sistemas.

207

Elementos de un diagrama de despliegue Los diagramas de despliegue presentan los siguientes elementos: Símbolo

Nombre

Propósito

Procesador

Representa equipos de hardware con capacidad de procesamiento computacional (por ejemplo una computadora personal o un servidor).

Dispositivo

Simboliza equipos de hardware sin capacidad de procesamiento (por ejemplo, un MODEM, dispositivos de red, entre otros).

Representa el hardware que Conector (la línea conecta dos equipos cualquiera sólida que (procesadores o dispositivos). conecta) Estos pueden ser conectores directos (por ejemplo cables de red) o indirectos (conexiones satelitales, celulares, etc.). Figura 67. Elementos de un diagrama de despliegue.

Construyendo un diagrama de despliegue La elaboración de un diagrama de despliegue debe apoyar la documentación de la disposición de los elementos del sistema – por ejemplo elementos de software - en equipos de hardware particulares. De igual forma, debe ayudarnos a visualizar qué conexiones deben realizarse para que la solución pueda funcionar. En otras palabras, estamos desplegando, visualmente, la arquitectura de equipos requeridos en la solución. Al respecto podemos hacernos preguntas como: ¿la solución deberá funcionar solo en la Intranet o también en Internet? Responder en uno u otro sentido nos puede llevar a configurar necesidades distintas de equipos. Por ejemplo, si la solución solamente se usará en la Intranet, no nos preocuparemos por aspectos como tener un firewall o un servidor Web con certificado de seguridad. Podemos imaginar esta situación para nuestro Sistema de Préstamo Bibliotecario: la solución puede funcionar, tanto en Intranet, como en Internet. Para este último escenario, podemos imaginar que la Universidad a la cual

208

pertenece la Biblioteca, tiene sedes regionales a las cuales, es difícil poder suministrarles un enlace privado11. La arquitectura n-capas nos puede ayudar en el proceso de construcción del diagrama de despliegue. En primera instancia podríamos preguntarnos qué equipo de hardware necesitaremos para la interfaz, lo que comúnmente llamamos, el equipo cliente (basado en la gran división de la arquitectura cliente/servidor). Podemos suponer que, tanto para la Intranet, como para Internet, se usará un equipo cliente representado por un Computador Personal (PC) que tenga un navegador Web. Este lo podríamos representar así: Cliente con Navegador

Figura 68. Equipo cliente del Sistema de Préstamo Bibliotecario.

Posteriormente tenemos que ver si este cliente está conectado directamente en la Intranet, o bien, debe pasar por un equipo especial de validación, como un firewall. Ambos esquemas de conexión deben llevarnos a un servidor Web donde reside el Sistema de Préstamo Bibliotecario. Tal esquema lo podríamos ver de la siguiente forma.

11

En este caso usted podrá notar que la solución que hemos modelado no tiene el concepto de Sede. Por lo tanto, nuestra Biblioteca tiene el modelo de una sola Biblioteca central. Para efectos de este ejemplo estamos imaginando que el Sistema Bibliotecario, como tal, puede tener varias bibliotecas y pueden gestionarse mediante el mismo sistema. Usted puede, como ejercicio, modificar los modelos que hemos realizado, de tal forma que incluya el concepto de Sede.

209

Cliente con Navegador

Firewall Universidad

Internet Red local Institucional

Red Local Institucional Servidor Web Biblioteca

Figura 69. Conexión hacia el Servidor Web de la Biblioteca desde Internet o Intranet.

Vemos cómo el equipo, si está en Intranet, se conecta al “Servidor Web Biblioteca”, donde reside el sistema, a través de la red local institucional. No obstante, si está en Internet, se usa esta red para que, en primera instancia vaya a un firewall, el cual resuelve la petición y traduce el direccionamiento externo a un direccionamiento interno hacia el Servidor Web de la Biblioteca12. Como parte de la solución, debemos considerar que nuestro sistema debe resolver aspectos relacionados con la base de datos (toda arquitectura de un sistema debe proporcionarnos una capa que interactúe con el servidor de base de datos que le da persistencia a la solución). Por lo tanto, a la Figura 69 le añadimos un equipo adicional, el cual representa el servidor de base de datos del Sistema de Préstamo Bibliotecario13:

12

El esquema que se presenta aquí puede ser mucho más complejo. En sí la temática de las conexiones desde Internet hacia los sistemas es muy amplio debido a la vulnerabilidad existente. Algunos equipos que pueden presentarse, como los firewall, los servidores seguros y otros, no necesariamente son equipos de hardware como tales, sino que son equipos de software o middleware especializados en seguridad y que podrían estar en un mismo equipo de hardware (puede darse, aunque no es recomendable, que esté en el mismo servidor Web donde están las aplicaciones). Sin embargo, es más fácil visualizarlos como dispositivos, tal como se muestra en la figura. El diagrama de despliegue podría ser mucho más preciso e identificar los equipos que albergarán software o middleware como los certificados de servidor seguro o un firewall. 13 Es necesario también reflexionar sobre lo siguiente: no necesariamente tendremos dentro de la infraestructura de una organización, un equipo especializado para cada una de las bases de datos que se vayan creando. Muchas veces tendremos conviviendo, en un mismo hardware distintas bases de datos de distintos sistemas. Sin embargo, para los efectos, en el diagrama de despliegue debemos identificar como tal el equipo en el que reside una base de datos particular. En el nombre de la “caja” que se representa, pueden adicionarse mayor información, como el nombre de la base de datos y del equipo.

210

Cliente con Navegador Firewall Universidad

Internet Red local Institucional

Red Local Institucional Servidor Web Biblioteca

Red Local Biblioteca

Servidor de Base de datos

Figura 70. Diagrama de despliegue del Sistema de Préstamo Bibliotecario.

En el esquema tenemos representados los elementos más importantes de la solución desplegados en equipos de hardware particulares. Note que en mucho puede aplicarse a una arquitectura en 3 capas vista en la Figura 32 del Capítulo 3. Sin embargo, el Servidor Web de la Biblioteca, puede contener los objetos para las capas de interfaz y de gestión. La división en “n-capas” pasa, en algunos casos, por una división lógica más que física en cuanto a equipos de hardware. Adicionalmente podemos pensar que el Sistema de Préstamo Bibliotecario debe interactuar con el Sistema Financiero de la Universidad. Por ejemplo, un caso de morosidad debe generar una cuenta por cobrar al Usuario involucrado y, si este cancela la mora, el Sistema Financiero debe comunicar al Sistema Biblliotecario que dicho Usuario ha dejado de estar moroso. Tal comunicación puede darse mediante Web Services dentro de la Intranet de la Universidad, por lo cual se usaría la red local institucional.

211

Cliente con Navegador

Firewall Universidad

Internet

Red local Institucional Red Local Institucional Servidor Web Biblioteca

Red Local Institucional

Servidor Web Financiero

Red Local Biblioteca

Servidor de Base de datos

Figura 71. Diagrama de despliegue del Sistema de Préstamo Bibliotecario integrando el

Sistema Financiero.

Note brevemente un dato que puede ser importante en la Figura 71. La conexión entre el Servidor Web de la Biblioteca y el Servidor de Base de Datos se hace mediante la Red Local de la Biblioteca. Esto significa, eventualmente, que los equipos principales de este sistema residen en la Biblioteca, por lo cual debe suponerse que la administración de los equipos recaerá en esta dependencia. No puede hacerse un juicio, a priori, si esto es conveniente o no. Todo dependerá de las políticas que cada organización puede tener al respecto, lo cual es tema de los cursos relacionados con la Administración de la Función de la Tecnología de Información. Por último, va a incluirse un dispositivo que es importante en nuestra solución y que da mucha agilidad al sistema: el lector de código de barras, el cual se comunica directamente con el equipo cliente. Con ello podemos tener una visión global de la estructuración de la solución en los distintos equipos de hardware involucrados.

212

Cliente con Navegador Firewall Universidad

Conector

Lector Código Barras

Internet Red local Institucional

Red Local Institucional Servidor Web Red Local Institucional Servidor Web Biblioteca Financiero

Red Local Biblioteca

Servidor de Base de datos

Figura 72. Diagrama de despliegue del Sistema de Préstamo Bibliotecario completo.

El conector del equipo cliente al lector de código de barras debe ser un cable directo a un puerto específico de dicho equipo. COMPLETANDO EL PROCESO DE TRANSICIÓN Con la visión arquitectónica de los diagramas de despliegue completamos, también, la apreciación acerca de elementos importantes necesarios en el sistema, como es el caso del hardware, software del sistema (servidores de bases de datos, servidores web, firewlall). Puede verse, de lo tratado anteriormente, que las pruebas de unidad y de integración, casi en su totalidad, se centran en comprobar lo correcto del comportamiento del software. No obstante los otros elementos del sistema involucrados, el hardware, los procedimientos, la documentación e incluso la gente, deben ser probados en su actuar conjunto para poder “sacar a la luz” el producto. Aspectos relacionados con la capacitación y adopción del producto, dentro de los responsables del proceso de uso del software y los procedimientos involucrados, son consideraciones que debemos tener con respecto a la gente. En ello, la documentación (descripción de procedimientos, manuales de usuario y técnico), será fundamental. 213

Por otra parte, debe probarse la interacción del software codificado, producto del proceso de Análisis y Diseño, con el hardware involucrado, con el software de sistema (servidor web y otros). Con ello debe completarse lo que en la Tabla Nº 8 vimos como “pruebas de sistema”. De forma resumida podemos ver cuánto aporta el desarrollo a través del Proceso Unificado, usando UML, en cada uno de los tipos de pruebas que deben realizarse. Tipo de prueba Prueba de unidad

Pruebas de integración

Pruebas del sistema

Modelos en UML usados Diagrama de actividad: especificación algorítmica de una operación. Modelo de clases: especificación de todas las operaciones en cada una de las clases. Diagramas de estado: garantizar que las operaciones respeten las transacciones válidas definidas. Modelo de clases: asociación entre clases. Diagramas de secuencia: interacción entre objetos de distintas clases para cumplir un caso de uso. Diagramas de actividad: cuando se usan para documentar el detalle de un caso de uso. Casos de uso: definición de los objetivos del sistema en los cuales las distintas piezas de software deben integrarse para cumplir tales objetivos. Diagramas de despliegue: definición de los elementos de hardware requeridos para poner en funcionamiento el sistema. Diagramas de casos de uso: definición de roles de la gente, definición de procedimientos del negocio. Modelos de UML creados: documentación técnica.

Tabla Nº 11. Relación entre los distintos tipos de pruebas y los modelos creados en el desarrollo del sistema.

Todos los modelos nos dan planos, tanto para la construcción del software y del sistema en general, pero al igual, con los mismos planos corroboramos que lo construído corresponda a la exigencia de lo solicitado. No debe olvidar que no solo debemos limitarnos a los requerimientos funcionales, es decir los que son producto de los que especificamos al lado de los clientes, sino que, además, debemos considerar los llamados requerimientos “no funcionales”. Por ejemplo, “garantizar que las transacciones sean registradas completas y de forma eficiente” no es algo que nos dirá el cliente, sino que es obligación nuestra, como ingenieros, que esto se cumpla. Al terminar todas las comprobaciones, en los distintos niveles de pruebas, podemos cumplir con los requerimientos de la fase de transición, con lo cual el sistema puede pasar a producción.

214

CONCLUSIONES Hemos hecho un largo recorrido, muy largo, tocando distintos trabajos que se realizan en la Ingeniería de Software, basados en los principios del Proceso Unificado usando UML y el Análisis y Diseño Orientado a Objetos. Este libro es introductorio a todas estas técnicas. Se ha tratado de abordar de forma inductiva, los procesos mediante los cuales se va creando la solución, usando los diagramas provistos por UML y aprovechando, de igual forma, las ventajas del Paradigma de Orientación a Objetos. Como tal es un proceso complejo, pero la complejidad, como se ha tratado de evidenciar, debe quedar en su capacidad de diseñador como ingeniero. Las herramientas de software y el UML, facilitan este proceso. Los modelos creados, a su vez, tienen una correspondencia directa en las clases que deben definirse en la programación del sistema. Por ello su esfuerzo, como ingeniero, se verá facilitado con el dominio de estas técnicas. Cada vez menos, los profesionales en desarrollo de software debemos a recurrir a metodologías poco claras y al uso de “monedas para hacer burbujitas”, como en el análisis estructurado, y que fue la experiencia que en mis primeros años viví personalmente. Temas más avanzados en estas mismas tecnologías, deberán facilitarse mediante el estudio de este libro. Para ello, ya se tiene el marco necesario para abordar temáticas como el desarrollo de componentes, desarrollo en tecnologías Web y arquitecturas orientadas a servicio.

215

EJERCICIOS DE AUTOEVALUACIÓN 1. Justifique la importancia de los casos de uso para poder tener pruebas de unidad y de integración. 2. Indique qué importancia tiene el modelo de clases para las pruebas de unidad? 3. Indique y justifique en qué procesos de prueba pueden servir: a) los diagramas secuencia, b) los diagramas de actividad c) los diagramas de estado. 4. Describa en qué medida pueden los componentes facilitar: a. La integración de piezas de software. b. Las pruebas de software en distintos niveles. c. La elaboración de la arquitectura del sistema. 5. Describa cómo el Proceso Unificado usando UML aporta en la definición de los elementos de un Sistema Basado en Computadora. 6. Para el Sistema de Reservación de Espectáculos en Línea realice lo siguiente. a. Indique qué diagramas pueden apoyar las pruebas de unidad. Ilustre con dos ejemplos de distintos tipos de diagrama. b. Lo mismo que en a.), pero para pruebas de integración. Esta vez ilustre con cuatro ejemplos. c. Defina dos componentes con sus interfaces y clases que lo integran. Justifique su elección. Indique cómo se acoplan esos dos componentes. d. Construya el diagrama de despliegue del sistema. e. Identifique los distintos elementos del Sistema Basado en Computadora para este sistema particular, a partir del trabajo elaborado en el proceso usando Proceso Unificado y UML. 7. Ejercicio práctico El ejercicio que presentamos a continuación pretende que aplique, de manera práctica e integral, los conocimientos adquiridos durante este curso. En él fuimos introduciendo, poco a poco, muchos de los modelos de UML en ciertos procesos de Análisis o de Diseño de software. Mencionamos, igualmente, que tales diagramas y técnicas no son exclusivos de las fases en que se estudiaron

216

y que, en problemas que se enfrentan en la Ingeniería de Software, pueden usarse de forma conveniente. Considere el siguiente caso. Una empresa dedicada al la prensa escrita, dada su cantidad de productos y la complejidad de procesos, ha decidido incorporar una serie de soluciones de software para apoyar la ejecución de sus tareas. Algunos de estos procesos se describen a continuación. - Producción de noticias. Los periodistas ingresan las noticias que elaboran mediante un software que captura el texto y las imágenes (que un fotógrafo haya hecho con relación a los acontecimientos). Las noticias deben pasar, primero por un proceso de corrección de estilo, el cual realiza un grupo de filólogos a los cuales el sistema les asigna una tarea específica. Luego, un editor, las agrupa en sucesos, deportes, reportajes, finanzas, etc., según corresponda y las clasifica según la importancia que tienen (primera plana, próxima edición, baja prioridad, etc.) y un diseñador gráfico realiza la diagramación, para finalmente enviarlas al proceso de reproducción. Este proceso incorpora, de forma digital, el diseño del periódico que hacen los diseñadores. La rotativa, que imprime los periódicos, realiza la reproducción de acuerdo con dicho diseño. - Producción de suplementos. Se sigue un proceso semejante al de las noticias. El suplemento, que se imprime semanalmente, puede estar produciéndose todos los días, sin que ello signifique que la planta de producción lo considere para el tiraje. Solamente el día que corresponda, se hará el tiraje de un suplemento. Pueden existir suplementos o insertos publicitarios que solo se distribuyen en un área determinada. - Distribución de periódicos. Conforme la planta de producción hace el tiraje, se crean los paquetes que deben distribuirse. Estos se agrupan en el tiraje, de acuerdo con parámetros tales como: • •

Área de distribución. Corresponde al área encargada de clasificarlos

según las regiones a las que van (por ejemplo que tengan un suplemento o insertos dirigidos para ciertas áreas geográficas). Cantidad de suscriptores. Corresponde al responsable que le da al software que administra la planta de producción de tiraje, un parámetro de cantidad que se une con otros parámetros como el de área de distribución.

217



-

Estimación de ventas por región. Cada agencia envía al sistema, un

resumen semanal de las ventas por día, así como la cantidad de las suscripciones activos. Con dicho parámetro, el sistema calcula una estimación de ventas para lograr un tiraje ajustado a la cantidad de ventas que se espera tener, además de las suscripciones.

Recaudación de suscripciones y ventas. El sistema refleja los ingresos

obtenidos por suscripciones y ventas depositadas en los bancos y las demás agencias que manejan la recaudación. Este ingreso se registra en el sistema financiero. Debe considerarse que la planta de producción tiene incorporado un software que permite realizar tirajes de un diseño de los productos que se hayan incorporado. Este tiraje lo hace de acuerdo con una fecha específica. El diseño se elabora de acuerdo con las notas que cada periodista realiza. Las notas son elaboradas desde sus estaciones de trabajo. El periódico tiene varias agencias en el país con el fin de que: a)

b) c)

Los periodistas o corresponsales que están en las regiones puedan ingresar sus noticias. Para ello la solución de software que debe capturar las noticias debe tener una interfaz en tecnología Web, para dotar al periódico de una Intranet (la cual aprovecha la red de Internet) que permita realizar tales trabajos. Se tramiten suscripciones y aspectos relacionados con la distribución local de periódicos. Se tramiten aspectos de publicidad en el periódico.

Con esta información, su trabajo consiste en realizar lo siguiente, teniendo en cuenta las fases del Proceso Unificado.

Fase de inicio a)

b)

c)

Definir los casos de uso críticos. Determine los casos de uso que considere son los más importantes de resolver para la Empresa. Estos casos de uso son los que, mayormente, definirían los elementos de software más relevantes de la capa de negocios. Definir una arquitectura de subsistemas de la solución. Para ello establezca un diagrama de componentes y una distribución en capas de la solución requerida. Considere para ello, todo el hardware y software especializado que pueda identificar. Elaborar una distribución inicial de tareas, de acuerdo con las fases y procesos que se desarrollan en el Proceso Unificado.

218

Fase de Elaboración Defina el diagrama de casos de uso del sistema. a) b) c) d) e)

Desarrolle la especificación de los casos de uso más importantes, tanto básica como detallada. Elija un caso de uso de los identificados como más importante y elabore un diagrama de clases conceptual. Compruebe la definición de las operaciones de las clases usando diagramas de secuencia y de actividad para documentar los casos de uso. Elija otro caso de uso importante y actualice el modelo de clases conceptual. Verifique las relaciones entre clases y las operaciones mediante tarjetas CRC para cada una de las clases definidas.

Fase de construcción a) b) c) d)

Retome el modelo conceptual de clases que hizo en la fase anterior y transfórmelo en un diagrama de clases de diseño para la capa de negocios. Elabore las capas de clases de diseño para la interfaz y la gestión. Documente los procesos de los gestores usando diagramas de secuencia para cada uno de los procesos que manejen los gestores. Defina los componentes correspondientes de acuerdo con criterios de cohesión y acoplamiento para los módulos identificados. Guíese por la definición de subsistemas identificados en la fase de inicio.

Fase de transición a) b)

Elabore el diagrama de despliegue de la solución. Elabore un plan de pruebas para dos de los componentes identificados.

219

BIBLIOGRAFÍA (Booch et al, 2001) Booch, G; Jacobson, I; Rumbaugh, J. El Proceso Unificado de desarrollo de software. Addison Wesley / Pearson Educación, España. (Fowler, 1999) Fowler, M; Kendall, S. UML gota a gota. Pearson Educación, México. (Hall, 2001) Hall, M. Servlets y Java Server Pages. Guía Práctica. Pearson Educación, México. (Larman, 2003) Larman, C. UML y patrones. Una introducción al análisis y diseño orientado a objetos y al proceso unificado. Segunda edición. Pearson Educación. México. (Laudon, 2004) Laudon, K; Laudon, J. Sistemas de información gerencial. Octava edición. Pearson Educación, México. (McConnell, 1997) McConnell, S. Desarrollo y gestión de proyectos informáticos. McGraw-Hill Interamericana de España, España. (Pressman, 2005) Pressman, R. Ingeniería del software. Un enfoque práctico. McGraw-Hill Interamericana, México. (Quatrani, 1998) Quatrani, T. Visual modelling with Rational Rose and UML. Addison Wesley, Estados Unidos

220