Entradas etiquetadas como modelado de caso de uso

Flujos de eventos alternativos

En un caso de uso, los flujos de eventos se refieren a los pasos que alternativamente van realizando los actores y el sistema en el contexto del requisito funcional capturado en el caso. Dichos pasos por claridad, se separan en el flujo principal y los flujos alternativos; de forma tal que en el flujo principal representamos el día feliz, donde todo ocurre sin problemas y en los flujos alternativos lidiamos con las situaciones de error y el comportamiento esperado del sistema en respuesta a dichos errores.

Es necesario entonces contar con una aproximación sistemática sobre como disponer los flujos de eventos principal y alternativos, de forma que capturen en forma clara y precisa cada condición que el flujo del día feliz ha asumido como libre de error pero que es a su vez, el punto de inicio de un flujo alternativo.

La idea aquí es la de indicar el paso del flujo principal y la condición precisa que de violarse hace que se ejecute el flujo alternativo. De ser posible la condición ha de estar expresada en términos del modelo de dominio de forma tal que facilitar su traducción al sistema software.

Los pasos del flujo alternativo han de tener una enumeración propia de forma tal que no choquen los unos con los otros ni con los pasos del flujo principal. La forma exacta en que vamos a enumerar es cosa de cada quien, por lo que es un punto a documentar como parte del Plan de Gestión de Requisitos, documento este que suele ser parte del Plan de Desarrollo de Software.

Un ejemplo de todo lo anterior puede ser visto como parte del ejemplo de caso de uso en este blog. En el ejemplo referido se hace mención al caso de uso “llamada de voz” y se ha señalado la condición de error “número incorrecto”. Veamos una versión ligeramente modificada del caso de uso de ejemplo para discutir como se puede implementar los flujos alternativos:

Código: CS-0100.
Nombre: Llamada de voz.
Actores: Usuario.
Descripción: El usuario del teléfono levanta el auricular y marca el número de destino. Al completar la secuencia de dígitos la conexión se realiza. Por medio de tonos particulares el sistema indica el estado de error y de progreso en la conexión.
Precondición: El teléfono está colgado.
Postcondición: Ninguna.
Diagrama:

Sencillo Modelo de Casos de Uso

Flujo Principal:
Paso 1 – Usuario:
Levanta el auricular.
Paso 2 – Sistema: Da el tono de marcado.
Paso 3 – Usuario: Indica el número de teléfono.
Paso 4 – Sistema: Realiza la conexión. Da tono de aviso en tanto se levanta el teléfono del lado contrario de la conexión. Permite la conversación al hacerse efectiva la conexión.
Paso 5 – Usuario: Conversa y al finalizar esta, tranca el teléfono.
Paso 6 – Sistema: Termina la conexión.

Flujo alternativo: Número incorrecto
Paso 3 – Sistema:
Presenta tono de error. El caso de uso termina.

Flujo alternativo: Desconexión inesperada
Paso 5.1 – Sistema:
Detecta un fin inesperado de la conexión. Indica todo de error.
Paso 5.2Usuario: Tranca el teléfono.
Paso 5.3 – Sistema: Registra error. El caso de uso termina.

Tabla 1 – Ejemplo de caso de uso con flujos alternativos

Como ya dije, este ejemplo es una modificación del ya visto en el post ejemplo de caso de uso, donde ahora se han considerado dos flujos alternativos, uno para la condición de número incorrecto y otro para la desconexión inesperada.

La condición ha sido indicada en términos abstractos, comprensibles desde una perspectiva técnica y luego se ha indicado el paso en que dicha condición se puede violentar. En el flujo alternativo del número incorrecto el paso es el tres y en caso de problemas las acciones a tomar son solo una: el sistema presenta tono de error.

Otro tanto puede ser dicho en el segundo flujo alternativo. La desconexión inesperada sin embargo a dado lugar a tres pasos. El sistema detecta un fin inesperado e indica tono de error. El usuario entonces tranca el teléfono. Finalmente el sistema registra el error. Estos tres pasos han sido enumerados con la secuencia 5.1, 5.2 y 5.3, de forma de hacer referencia a que son un flujo alternativo del paso cinco del flujo principal al tiempo de mantener una secuencia numerica propia.

, , , , , , , , ,

7 comentarios

El flujo de eventos del día feliz

Un flujo de eventos consiste en enumerar los pasos que sucesivamente realizan los actores y el sistema en el contexto de un caso de uso. Es decir, que un flujo de eventos es en su forma más básica un simple listado de acciones, que corresponden con un caso de uso en concreto.

Si pensamos un poco en el tema nos podemos percatar que la funcionalidad promedio de un caso de uso ha de tener bifurcaciones e incluso bucles. Esto es natural pensarlo ya que hay una similitud muy fuerte entre la noción de algoritmo y la de flujo de eventos vistos estos como listado de pasos.

Sin embargo, a diferencia de las notaciones formales utilizadas para expresar algoritmos, los flujos de eventos se construyen en lenguaje natural, lo cual impone limitaciones sobre cuan precisamente podemos indicar condiciones y bifurcaciones sin comprometer la claridad.

La solución a este problema claro esta, es la de tener más de un flujo de eventos. Tendremos uno sencillo y claro, que exprese lo que ha de ocurrir en el caso más probable y a su vez, tendremos otros flujos alternativos que lidien con las condiciones de error o casos que requieran bifurcación.

Al flujo de eventos principal, ese que contiene el caso más probable, se le llama Flujo de Eventos del Día Feliz, como forma de hacer referencia a la ausencia de condiciones de error. En otras palabras, le llamamos día feliz ya que en este flujo de eventos principal vamos a asumir que todo ocurre de la mejor forma: el actor tiene disponible la información y la indica sin fallas, el sistema puede completar todas las operaciones y así sucesivamente para cada posible desviación. En el flujo del día feliz simplemente todo ocurre correctamente.

, , , , , , , ,

7 comentarios

Todo requisito debe ser preciso y legible

La especificación de un sistema es un trabajo retador. En él participan no solo los desarrolladores de aplicaciones, sino también los clientes. Esto significa que la especificación de requisitos, ya sea como casos de uso o como declaraciones tradicionales tipo “el sistema debe…” ha de ser entendida a la vez, por lo clientes y por los desarrolladores. Dicho en otras palabras: la especificación contiene detalles técnicos que los clientes luchan por entender, a la vez que incluye información sobre el negocio que es nueva y potencialmente confusa para los desarrolladores.

Esta situación nos obliga a luchar por dos atributos básicos en todo nuestro sistema de requisitos: la claridad y la precisión.

Precisión de un requisito. Un requisito es preciso cuando indica sin ambigüedad lo que se desea especificar. Debe ir directo al punto y evitar todo adorno en el lenguaje. Debe documentar solo un aspecto del sistema y lo debe de hacer en forma exacta.

Y también

Claridad o legibilidad de un requisito. Un requisito es legible cuando el lenguaje en el que esta escrito es fácil de entender, tanto por los clientes como los analistas. La legibilidad se extiende no solo a la especificación escrita, sino también a los formalismos gráficos como los diagramas de casos de uso.

Es curioso observar que en los cursos universitarios sobre el tema, los profesores tengan la presión de explicar métodos y técnicas avanzadas, como las relaciones de extensión e inclusión de casos de uso, forzando al estudiante a adoptar estar técnicas en forma demasiado temprana. Esto causa una deformación profesional en el estudiante, quien sale del curso con la creencia que es mejor una especificación sofisticada que haga uso de todo lo visto en el curso, en lugar de una aproximación más informal y relajada que puede en verdad ser entendida por el cliente.

El lugar correcto para la extensión y la inclusión, así como para todas las técnicas de modelado de requisitos más sofisticadas, es en aquellos dominios de aplicación donde los requisitos reales sean muy complejos. Es decir por lo tanto, que en la práctica el analista ha de hacer esfuerzos por mantenerse sencillo, normalmente no vale la pena la complejidad del modelo de requisitos.

También es de hacer notar, que en mi experiencia la mayoría de los clientes intentan hacer otro tanto. Ellos suelen expresar lo que necesitan en la forma más directa que tienen disponible, sin embargo dado que los clientes son a su vez profesionales en un área especifica, la forma correcta en la ellos se expresan suponen tensión a los desarrolladores, quienes deben luchar por desarrollar un vocabulario común con el cliente para poder comprender sin errores lo que este pide.

En conclusión: lo sencillo se entiende más y la especificación de un sistema ha de entenderse bien. Cuan sofisticado hagamos nuestro modelo de casos de uso o nuestro documento de especificación, no es ni de lejos lo que en verdad importa. Es mucho mejor un caso de uso sencillo pero que captura valor de negocio, que uno sofisticado que haga un uso abundante de las técnicas más esotericas de modelado.

, , , , , , , , , , ,

2 comentarios

Casos de Uso: Herencia de Actores

La propiedad de mayor interés de los actores, más allá de su identidad, es la relación que estos guarden con los distintos casos de uso de nuestro sistema – las líneas que unen a unos con otros. Es decir que las dos partes más expresivas de un actor son el nombre propio y la activación de un caso de uso.

Aceptado lo anterior, la herencia de actores va a ser la distribución a lo largo de una jerarquía de roles, de las actividades a realizar, representadas estas como casos de uso. O lo que es lo mismo, la herencia nace como una forma de organizar los enlaces entre actores y casos de uso a fin de simplificar los diagramas y reducir la necesidad de presentar información repetida.

Nuevamente pero algo más técnico: a lo largo de la jerarquía de herencia lo que vamos a organizar son las activaciones de casos de uso de cada actor con ayuda de categorías intermedias o actores abstractos.

A diferencia de la herencia de casos de uso, considero que la herencia de actores es una práctica básica y que no tiene mayor problema en ser entendido por los stakeholders ni mucho menos, presenta problemas a los analistas. La razón es que la dificultad de la herencia de los casos de uso es la definición detallada de como los múltiples elementos de información de un caso de uso se comporta durante la herencia, dificultad esta que no existe en la herencia de actores por ser estos tan sencillos.

Como dije antes, la herencia de actores es una forma legible de mejorar la presentación de nuestros modelos, por lo que ejemplo que daré tiene por motivación el mejorar la legibilidad de un por lo demás, muy sencillo modelo de casos de uso.

A efectos del ejemplo, supongamos que trabajamos con un sistema de ventas, que permite tanto a los promotores como a los empleados del departamento de ventas el visualizar las existencias de productos así como la consignación de mercancía, pero que excluye a los promotores de la posibilidad de aceptar devoluciones. La situación es presentada en el siguiente diagrama de casos de uso:

Ejemplo de modelo de casos de uso sin herencia

Fig. 1 – Ejemplo de modelo de casos de uso sin herencia

Si se observa con atención el diagrama 1, se ve como las líneas de activación se cruzan entre actores. Claro que podemos tratar de organizar un poco mejor el diagrama para evitar esto, pero hemos de reconocer que esto solo será una solución temporal. Conforme se incremente la cantidad de casos de uso nos encontraremos una y otra vez en esta situación. No es solo una cuestión de estética, de utilizar líneas segmentadas bien podríamos llegar a hacer el diagrama por completo ilegible. Es entonces necesario un enfoque alternativo.

Dicho enfoque alternativo naturalmente va a ser la herencia. En el segundo diagrama se ven exactamente los mismos casos de uso y los mismos actores, pero se ha establecido una relación de herencia con respecto a un actor abstracto u operador como estrategia para presentar la información sin tanto barullo de líneas.

Ejemplo de modelo de casos de uso con relación de herencia entre actores

Fig. 2 – Ejemplo de modelo de casos de uso con herencia entre actores

En este segundo diagrama hemos indicado que el operador puede realizar las dos tareas comunes, en tanto que por herencia hemos dicho que los empleados del departamento de ventas son los únicos autorizados a aceptar devoluciones de mercancías. Aquí hay que notar que no he establecido una relación de herencia entre promotor y ventas, sino que por el contrario he introducido un actor abstracto nuevo, que articula la presentación del modelo sin correr el riesgo de equivoco: promotor no es ventas y ventas no es promotor. El hecho que compartan dos casos de uso si es algo digno de mención pero sus identidades siguen por completo desligadas.

La presencia de un actor abstracto puede ser considerada una fuente de ruido a la hora de explicar el modelo, pero dado que es solo para simplificar las líneas de activación encuentro que la sobrecarga de información no es nociva. Por otra parte lo que hemos ganado en claridad es en mi opinión, mucho mayor a lo que hemos sacrificado al utilizar una notación un poco más técnica.

, , , , , , , , , ,

13 comentarios

Un buen requisito debe ser atómico

“Un buen requisito debe ser atómico” lo digo y lo repito: Un buen requisito debe ser atómico. Sin embargo esto no significa que debe guardar alguna relación con la industria militar o la energía atómica. Si bien el átomo es un concepto de la ciencia moderna, el adjetivo atómico significa indivisible o dicho en otras palabras: único, singular, no susceptible a ser dividido.

Claro que eventualmente lo vamos a analizar y de ahí, que propongamos una relación de objetos que al colaborar den a lugar la funcionalidad requerida; pero el requisito en si mismo ha de describir un único requisito.

Y es que ocurre que en ocasiones un analista despistado, construye un cuerpo de requisitos donde uno o más de estos, contiene alguna forma de declaración compuesta, de forma que se refiere sin querer, a más de una característica.

La misma necesidad de atomicidad es requerida en los casos de uso. Un buen caso de uso debe hablarnos de un escenario de interacción completo y singular de manera que pueda ser tomado como una unidad indivisible.

Varios trucos se pueden dar para lograr este criterio de atomicidad: evitar las declaraciones compuestas y referirse en todo momento a una única característica son solo las dos primeras que me vienen a la mente. Sin embargo, como las recetas universales siempre tienen casos en que fallan, me limitaré a solo indicar lo que queremos: un requisito de buena calidad siempre ha de ser atómico.

El como lo logre el analista de requisitos es más cosa de habilidad que de consejos leídos por ahí.

, , , , , , , , , ,

5 comentarios

Un buen caso de uso captura valor de negocio

Una de las principales dificultades a la hora de desarrollar un cuerpo de requisitos para un sistema es el hecho innegable de la diferencia de formación entre los profesionales del desarrollo de software y los clientes de estos.

En tanto los desarrolladores cuentan con experiencia en algoritmia, análisis o modelado, los clientes suelen tener formación en contabilidad, finanzas, construcción o quien sabe en qué. Esta diferencia se extrapola a los puntos de vista de cada lado de la mesa, por lo que a la hora de definir el sistema que se desea es inevitable que el desarrollador note vacíos o faltas en la especificación (puntos como: seguridad, gestión de datos y otros aspectos técnicos) a la vez que el cliente puede hacer mucho hincapié en aspectos que a primera vista y desde el punto de vista del desarrollador son menos urgentes o se explicaron ya con unas pocas palabras.

Un poco por lo anterior es la muy conocida queja contra los clientes “no saben lo que quieren” pero en verdad la queja es debida a un fallo en el análisis del profesional de computación: los clientes especifican lo que les preocupa y esto no es ni de lejos, una especificación completa para una aplicación.

Paradójico quizás, en el sentido en que es contrario a la intuición de algunos, pero es que los clientes deben ver que los sistemas que solicitan responden a sus necesidades y aspectos técnicos que son del conocimiento del desarrollador los ven como parte de la solución técnica propuesta por este; lo que el cliente especifica es de valor para él y lo que no especifica es el margen de maniobra que se usa en la busqueda de la mejor solución técnica posible.

De todo lo anterior se desprende una regla básica para obtener un buen requisito y de ahí, un buen caso de uso: todo caso de uso ha de capturar valor de negocio. No hacemos casos de uso para especificar el comportamiento técnico del sistema, por lo que no tenemos casos de uso para indicar el ingreso al sistema o la generación de copias de seguridad. Si tales cosas no son del interés directo del cliente lo mejor es dejarlas por fuera del modelo de casos de uso. En cambio, aspectos quizás irrelevantes como la generación de un reporte o la aprobación de un supervisor a un paso del flujo de trabajo de la aplicación ha de representarse como caso de uso ya que es de interés para el cliente y le ayuda a decir lo que quiere decir sobre el sistema.

, , , , , ,

Deja un comentario

Casos de Uso Avanzados: Relación de Inclusión

El modelado de casos de uso persigue capturar la funcionalidad del sistema visto desde el punto de vista de sus operadores –actores– por lo que es fundamentalmente una construcción de elementos de modelado comprensibles por los clientes –stakeholders– y no solo por los analistas.

Sin embargo, en ocasiones es conveniente introducir algunos pocos elementos que no sean directamente los conceptos que manejan los clientes. Por ejemplo, en aras de evitar la redundancia, es posible pensar en extraer algunos fragmentos que nos permita indicar en uno o más casos de uso este fragmento repetido, por referencia en lugar de repetirlo en cada caso.

A este proceso de extracción del fragmento repetido lo modelamos por medio de la relación de inclusión <<include>>, tal como se ve en el siguiente diagrama:

Fig. 1 – Relación de inclusión entre casos de uso

En la figura, el caso de uso “A” es un fragmento, que define un trozo de un flujo de eventos que es referido por el caso de uso “B”. En este tipo de relación, el caso incluido (el “A”) debe ser un fragmento, nunca un caso concreto, en tanto que el caso que incluye (el “B” del ejemplo) si ha de ser un caso de uso completo.

A diferencia de la relación de extensión, aquí ninguno de los casos de uso involucrados puede ser entendidos por completo como piezas aisladas. Por un lado, el caso incluido es solo un fragmento, por lo que no es posible considerarlo un caso de uso pleno; en tanto que el caso que incluye al hacer referencia a un fragmento externo tiene necesariamente que ser entendido en presencia del fragmento.

Formalmente, como para el glosario:

Relación de Inclusión <<include>> Un caso de uso concreto incluye a un fragmento de caso de uso, cuando como parte de su descripción breve o su flujo de eventos, se hace referencia al texto del fragmento; de forma tal que lo dicho en el fragmento pasa a ser parte de la especificación del caso de uso.

Para lograr que se entienda el concepto, nada mejor que un ejemplo. Supongamos que estamos hablando de un sistema de gestión de agenda de un empresas con gerentes y asistentes. En este sistema hemos identificado dos casos de uso:

Código: UC-0100.
Nombre: Acepta cita.
Actor: Gerente.
Descripción: El Gerente visualiza su calendario de citas y aprueba aquellas citas que desee aceptar.

Código: UC-0200.
Nombre: Coordina cita.
Actor: Asistente.
Descripción: El asistente busca un momento apropiado para las citas pendientes al visualizar el calendario de citas del Gerente. Indica para cada cita propuesta la descripción, el día y la hora.

Tabla 1 – Casos de uso del sistema

Como se nota, en ambos casos se requiere de visualizar la agenda. Es posible imaginar que esta función abarca no solo la visualización del calendario, sino también ciertas funciones de búsqueda y filtrado por criterios. Para especificar esta funcionalidad pero evitar hacerlo en cada uno de los flujos de eventos de los casos de uso ya definidos, se opta por crear un fragmento que contenta esos detalles e incluirlo en los casos de uso originales. La situación da lugar al siguiente diagrama:

Fig. 2 – Modelo de casos de uso con un
ejemplo de relación de inclusión

De esta forma, evitamos tener que definir en múltiples lugares una misma funcionalidad. Sin embargo, el fragmento que se incluye ha de ser visto siempre como lo que es: un fragmento sin significado completo. En verdad es una lastima que de momento no tengamos una forma de marcar a los fragmentos de manera que se diferencien a simple vista de los casos de uso. Sugiero que al menos, en tanto surge un estereotipo estándar para esta tarea, tengamos una serie de numeración particular para los fragmentos. O bien, tomar la iniciativa y definir un estereotipo de UML por nosotros mismos.

Naturalmente que a la hora de hacer la especificación detallada de los casos de uso, en particular en los flujos de eventos, debemos marcar muy claramente en que lugar se ha de realizar la inclusión de lo dicho en el fragmento.

La relación de inclusión es claramente diferente a la relación de extensión y espero que haya quedado claro. La inclusión es una relación entre un caso de uso concreto y un fragmento, en tanto que la extensión involucra casos de uso concretos.

Por otra parte, a diferencia de la relación de extensión, la inclusión en cierta forma modifica al caso que incluye, por cuanto el fragmento define una parte de la funcionalidad del caso de uso completo. Esto significa que el caso de uso que incluye no puede ser entendido por completo en ausencia del fragmento que se incluye; algo muy diferente a la situación en una relación de extensión.

, , , , , , , , , , , , ,

30 comentarios