Los casos de uso (IV)

Pautas para detallar buenos casos de uso

Lo primero que debe hacerse es crear una visión de conjunto, es decir, tomar los casos de uso encontrados, agrupar aquellos que estén relacionados y describir brevemente sus objetivos. De esta forma, el cliente tendrá la oportunidad de efectuar revisiones tempranas. Posteriormente, los casos de uso se especificarán incrementalmente, es decir, para aquellos casos donde una descripción sea insuficiente, se empezará escribiendo el escenario principal, se continuará identificando las extensiones, detallándolas y refinando el modelo constantemente.

Tanto si se ha optado por el modo ordinario como por el formal, no debe cometerse el error de escribir todos los epígrafes y detalles de un caso de uso de una vez. Este enfoque es ineficaz y encierra el riesgo de crear casos incoherentes. Cuando comienza un nuevo proyecto poco se sabe del sistema a desarrollar, se tiene una idea de qué debe hacer pero se desconocen los pormenores. La especificación de casos de uso es un proceso iterativo en el cual el modelo y los detalles se refinan continuamente. Al fin y a la postre, la toma de requisitos es un aprendizaje constante sobre la misión del sistema.

Un caso de uso debe describir una pieza manejable de trabajo independiente y cohesiva que determine una parte del comportamiento del sistema. Simultáneamente, debe tener un tamaño que permita entenderlo, es decir, que no abrume por tener decenas de pasos y un exceso de detalles. Adolph y Bramble [1] citan varios factores a tener a cuenta para controlar la complejidad de un caso de uso:

  • Un caso de uso excesivamente largo puede ocultar su propósito en un mar de detalles, además de impedir su reutilización.
  • Un caso de uso excesivamente pequeño puede describir únicamente una parte del objetivo a alcanzar, por lo que no sería independiente ni cohesivo.
  • El desconocimiento del dominio conduce a encontrar casos de uso pequeños ligados a la tecnología que ─se asume─ se empleará en el desarrollo del sistema.

A la hora de redactar los casos de uso debe evitarse toda forma ambigua. Aunque cierta ambigüedad pueda ser tolerable en algunos casos de uso secundarios, puede hacer saltar por los aires el proyecto. Ahora bien, detallar los casos de uso excediendo las necesidades reales del cliente y el equipo técnico es un desperdicio de recursos y una pérdida de tiempo. La mentalidad de los ingenieros les conduce a ser bastante formales en sus descripciones, pero si se convierte en una obsesión será fácil caer en la parálisis por sobreespecificación de los casos de uso principales. Un caso de uso sobreespecificado puede ser engañoso para el cliente si piensa que los requisitos son más precisos de lo que realmente son. He aquí un ejemplo hiperbólico de sobreespecificación:

Caso de uso: Usar DEG
El usuario empleará un Dispositivo de Escritura de Grafito (DEG) formado por un prisma hexagonal de entre 15 y 18 cm elaborado en madera fina de tilo que encapsulará una barra de 2 mm de diámetro compuesta por grafito y arcilla. El DEG exhibirá colores negro y amarillo de manera alterna en las caras del prisma.

¿Tanto para decir que debe usarse un lápiz? El ejemplo es casi cómico, pero en documentos de especificación procedentes del mundo militar pueden llegar a encontrarse textos con este cariz.

Por tanto, hay que evitar ser ambiguo o demasiado excelso a la hora de detallar un caso de uso. Si se tiene la certeza de que algún paso puede estar mal, es mejor no detenerse en exceso. Errores así son relativamente fáciles de subsanar y, en cualquier caso, paralizar el proyecto siempre tiene un coste mayor. Además, no hay que olvidar que los casos de uso siempre deben revisarse.

Estas pautas pueden ser útiles para depurar los casos de uso:

  • Identificar cuál es el punto inicial del caso de uso, es decir, qué suceso desencadena el actor.
  • Identificar cuál es el punto final, es decir, el resultado o servicio que el sistema proporciona al actor. Esto ayudará a delimitar el tamaño.
  • Buscar posibles duplicados. Quizá haya casos de uso con distinto nombre que en realidad son el mismo.
  • Identificar qué actores necesitan los mismos casos de uso. Ayudará también a eliminar duplicados o unir varios casos de uso en uno.

También hay que intentar encontrar un equilibrio en la redacción para que el caso no sea demasiado difícil de leer para el cliente o demasiado impreciso para los ingenieros. Los casos de uso que pecan de esta característica dan lugar a un desarrollo pobre y a un sistema deficiente. Debe procurarse:

  1. No incluir detalles de implementación, ni menciones a la interfaz gráfica de usuario, ni referencias tecnológicas porque aumentará la complejidad de la lectura e impedirá la reutilización del caso por el carácter volátil de la tecnología. Hay excepciones a esta regla: el sistema en desarrollo debe trabajar con sistemas externos con protocolos específicos, acceder a bases de datos con gestores concretos o cumplir con normas de carácter industrial, militar o legal.
  2. Jamás debe crearse un doble modelo de casos de uso: uno para el cliente y otro para el equipo técnico. El coste de mantenimiento se dispará y, aún peor, ambos modelos terminarán divergiendo.

El cuerpo de todo escenario son las acciones ─los pasos─ que forman la secuencia. Si se escriben pasos demasiado breves y en gran número, el caso resultará más difícil de comprender y distraerá al lector del porqué del escenario. Por otro lado, si los pasos son demasiado largos el comportamiento reflejado en el escenario puede quedar opacado. Es fácil escribir un exceso de detalles, pero esto perjudica el entendimiento. Los pasos que no hagan avanzar al actor y los detalles que distraigan al lector sobre el progreso del actor deben eliminarse o combinarse con otros pasos.

Cada escenario debería contar con un número de pasos comprendido entre tres y diez (número orientativo, no dogmático), todos al mismo nivel de abstracción ─si se está describiendo un caso de nivel objetivo no tiene sentido descender a detalles típicos de los casos de nivel subfunción─. Asegúrese de que quede claro qué actor tiene la responsabilidad de realizar un paso concreto y qué pretende conseguir al darlo.

Considere que un caso de uso está finalizado cuando:

  • Identifica los actores y sus objetivos.
  • Sigue el modo y formato acordado por el equipo.
  • Es lógicamente correcto.
  • Es legible para su revisión por el cliente.
  • Es suficientemente preciso para que los ingenieros pueden desarrollarlo.
  • El cliente lo ha revisado y aprobado.

Articulación de los casos de uso

Al tratar la búsqueda de casos de uso se comentó que el proceso de refinado puede dar lugar a la división, unión, aparición y desaparición de casos. Un hecho típico que origina la división de un caso de uso se da cuando una parte de la secuencia se repite en otros.

Por ejemplo, en el caso de uso «Efectuar reintegro», los cuatro primeros pasos hace referencia a la lectura y validación de la tarjeta y la clave del usuario:

Caso de uso: Efectuar reintegro.
...
Pasos:
 1. El usuario introduce la tarjeta. 
 2. El cajero valida la tarjeta.
 3. El usuario introduce su número de identificación personal (PIN).
 4. El cajero valida el PIN.

Es fácil advertir que esta secuencia se repetirá en todos y cada uno de los casos cuyo actor principal es el usuario:

  • Efectuar reintegro
  • Realizar depósito
  • Consultar saldo
  • Consultar movimientos
  • Realizar transferencia
  • Pagar impuestos
  • Pagar recibos
  • Cambiar clave

Así las cosas, parece razonable extraer los pasos de la secuencia y crea un nuevo caso de uso llamado «Autenticar tarjeta». Desde los demás casos se incluirá éste desde un paso con el texto subrayado. Si es necesario, puede indicarse también el nuevo caso de uso de forma explícita.

Caso de uso: Efectuar reintegro.
Actor principal: Usuario.
Pasos:
 1. El usuario autentica la tarjeta. [Caso «Autenticar tarjeta»]
 2. El usuario introduce una cantidad de dinero.
 3. El cajero valida la cantidad.
 4. ...

Dado que el nuevo caso de uso no produce un resultado observable y de interés para el actor, porque nadie va a un cajero simplemente a validar su tarjeta y no hacer nada más, el caso pertenece al nivel subfunción en lugar de al nivel objetivo. Además, las extensiones directamente relacionadas con los pasos implicados también deberán trasladarse, lo que reduce el tamaño del caso de uso original, algo que siempre es positivo.

Caso de uso: Autenticar tarjeta.
Actor principal: Usuario.
Nivel: Subfunción.
Pasos:
 1. El usuario introduce la tarjeta. 
 2. El cajero valida la tarjeta.
 3. El usuario introduce su número de identificación personal (PIN).
 4. El cajero valida el PIN.
Extensiones:
E01. Usuario no responde.
     *a. El cajero detecta que han transcurrido 40 segundos desde la última acción del usuario.
         *a1. El cajero archiva la tarjeta.
         *a2. Fin del escenario.
E02. Tarjeta inválida.
     2a. El cajero no puede leer la tarjeta.
         2a1. El cajero informa de posibles daños en la banda magnética.
         2a2. Fin del escenario.
     2b. El cajero detecta que la tarjeta está caducada.
         2b1. El cajero informa de la caducidad de la tarjeta.
         2b2. Fin del escenario.
E03. PIN inválido.
     4a. El cajero rechaza el PIN por primera o segunda vez.
         4a1. Ir al paso 3.
     4b. El cajero rechaza el PIN por tercera vez.
         4b1. Fin del escenario.
Variantes tecnológicas:
1a. Lector de banda magnética y lector de microchips.

La extracción de los casos de uso de la forma expuesta no sólo es aplicable a la secuencia del escenario principal sino también a las extensiones.

En UML, cuando un caso de uso incluye a otro se expresa mediante la relación «include» tal y como se muestra en la siguiente figura.

La relación «include»

Dado que todos los casos de uso del usuario requieren la inclusión de «Autenticar tarjeta», en lugar de crear un diagrama donde todos lo incluyan, es mejor hacer referencia a él en el epígrafe «Precondición» donde ─como recordará─ se indica qué debe ser cierto antes de que el caso de uso dé comienzo.

Caso de uso: Efectuar reintegro.
Actor principal: Usuario.
Precondición: El usuario ha autenticado la tarjeta. [Caso «Autenticar tarjeta»].
Pasos:
 1. El usuario introduce una cantidad de dinero.
 2. El cajero valida la cantidad.
 3. ...

La relación de inclusión puede ser útil para estructurar el modelo de casos de uso, pero no debería abusarse de ella. Dividir casos de uso individuales tiende a dispersar su comportamiento y los hace más difíciles de entender. Habitualmente solo hay dos situaciones donde sí merece la pena emplearla:

  • Una secuencia de pasos o una extensión es común a dos o más casos de uso. El nuevo caso de uso será de nivel subfunción tal y como se ha visto en el ejemplo expuesto.
  • Una extensión se vuelve tan compleja que merece la pena extraerla para tratarla de forma independiente.

Por otra parte, habrá ocasiones en que sea necesario un tipo de relación diferente pero muy parecida al mecanismo de creación de extensiones. Cuando una extensión afecta a más de un paso del escenario, es conveniente crear un caso de uso a partir de ella para evitar confundir al lector o hacerle perder de vista la información relevante. A ese nuevo caso de uso se le denomina de extensión, pero hay una importantísima diferencia con una extensión propiamente dicha: los casos de uso de extensión son servicios asíncronos que el actor puede usar o llevar a cabo en cualquier momento de la secuencia del caso de uso base.

En lugar de complicar el caso de uso base incluyendo en todos los pasos el servicio que el actor puede utilizar, se crea el caso de uso nuevo. Por ejemplo, el usuario del cajero puede cancelar la operación en curso en cualquier momento, por lo que parece razonable crear un caso de extensión denominado «Cancelar operación» en lugar de tenerlo en cuenta a la hora de detallar el caso de uso.

Para crear un caso de uso de extensión se sigue el mismo esquema empleado para crear una extensión. Posteriormente, se emplea el epígrafe «Desencadenante» para indicar qué suceso provoca la ejecución.

Caso de uso: Cancelar operación.
Actor principal: Usuario.
Desencadenante: En cualquier momento en «Efectuar reintegro».
Pasos:
 1. El usuario cancela la operación.
 2. El cajero valida que la operación no se ha confirmado.
 3. El cajero expulsa la tarjeta.

Hay que ser muy prudente a la hora de crear casos de usos de extensión. Deben evitarse en la medida de lo posible pues la experiencia demuestra que son difíciles de entender y costosos de mantener.

En UML, un caso de uso de extensión se expresa mediante la relación «extend» tal y como se muestra en la siguiente figura.

La relación «extend»

Dado que la frontera entre las relaciones «include» y «extends» es muy difusa, he aquí unas pautas que pueden ayudar a distinguir si un caso es de inclusión o de extensión:

  • Si el caso de uso base sabe cuándo invocar a otro caso de uso entonces el primero incluirá al segundo, es decir, el caso de uso sabe bajo qué condiciones se pondrá en marcha el caso de uso incluido. Dicho de otra forma, el caso de uso base llama explícitamente al segundo, pero éste no sabe quién lo llama. Fíjese cómo el caso de uso «Efectuar reintegro» hace mención explícita (texto subrayado) al caso de uso «Autenticar tarjeta». Sin embargo, en «Autenticar tarjeta» no hay ninguna referencia al caso de uso que lo llama.
  • Si un caso de uso sabe cuándo se lanzarán sus acciones entonces éste extenderá un caso de uso base, es decir, el caso de uso sabe bajo qué condiciones puede ejecutarse. En otras palabras, el caso de uso de extensión hace referencia al caso de uso base en el epígrafe «Desencadenante», pero el base no menciona en ningún momento al de extensión. Observe cómo el caso de uso «Cancelar operación» menciona explícitamente al caso de uso «Efectuar reintegro» en el epígrafe citado, pero éste último no hace referencia alguna a «Cancelar operación».

Para finalizar, se expondrá una manera diferente de articular las variantes tecnológicas. Como recordará, el caso de uso «Autenticar tarjeta» incorporaba el epígrafe «Variantes tecnológicas»:

Caso de uso: Autenticar tarjeta.
Actor principal: Usuario.
Nivel: Subfunción.
Pasos:
 1. El usuario introduce la tarjeta. 
 2. El cajero valida la tarjeta.
 3. El usuario introduce su número de identificación personal (PIN).
 4. El cajero valida el PIN.
Extensiones:
...
Variantes tecnológicas:
1a. Lector de banda magnética y lector de microchips.

Obviamente, las dos variantes terminan haciendo lo mismo: leer los datos de la tarjeta aunque por medios diferentes. Si existiera la necesidad de detallar dichas variantes ─algo bastante probable─ en un par de casos de uso de nivel subfunción, se pueden articular como los casos concretos de uno abstracto llamado «Leer tarjeta». De esta manera, desde el caso de uso principal se puede hacer simplemente referencia al abstracto «Leer tarjeta» como caso incluido y suprimir el epígrafe «Variantes tecnológicas». Los casos de uso abstractos se denotan en cursiva.

Caso de uso: Autenticar tarjeta.
Actor principal: Usuario.
Nivel: Subfunción.
Pasos:
 1. El usuario introduce la tarjeta.
 2. El cajero lee la tarjeta. [Caso «Leer tarjeta»]
 3. El cajero valida la tarjeta.
 4. El usuario introduce su número de identificación personal (PIN).
 5. El cajero valida el PIN.
Extensiones:
...

Para indicar en el modelo de casos de uso la relación entre un caso de uso abstracto y aquellos que lo concretan ─llamada relación de generalización─ se emplea una flecha con punta hueca. Por ejemplo, así queda la relación entre el caso «Autenticar tarjeta», el caso abstracto incluido y sus dos concreciones:

La relación de generalización

Referencias

[1] Steve Adolph y Paul Bramble. Patterns for Effective Use Cases. Addison Wesley, 2002.

Fotografía de la entrada creada por Freepik

Entradas relacionadas