domingo, 25 de enero de 2009

Metodología de desarrollo software

Metodología de desarrollo software

FASES

Las fases en las que hay que desarrollar un proyecto, son básicamente Requisitos, análisis, diseño preliminar, diseño detallado, codificación y pruebas.

REQUISITOS

Los requisitos son una lista de cosas que queremos que haga nuestro programa. Lo normal es que recopilemos dicha lista hablando con todas las personas que podamos: usuarios de nuestro programa, expertos en el tema de que trata el programa, etc.

Normalmente la gente con la que hablemos nos dará los requisitos de una forma vaga y desordenada. Es labor nuestra ordenarlos (por temas, por dificultad, por importancia para los usuarios, etc.) y asegurarnos de que son claros.

Para asegurarnos de que un requisito es claro, debemos saber qué persona lo ha propuesto y por qué lo ha propuesto, qué es lo que cree exactamente que vamos a hacer en nuestro programa cuando nos ha dicho ese requisito.

ANÁLISIS

Durante el análisis vamos a definir más claramente qué es lo que va a hacer nuestro programa. Debemos hacer varias cosas principalmente:

  • Identificar actores. En lenguaje UML, actores son los usuarios y cualesquiera otros sistemas con los que se pueda comunicar nuestro programa. En nuestro programa de ajedrez, un actor sería el usuario que va a jugar al ajedrez. Le llamaremos "jugador". También se indicaba como requisito que pueda aprender aperturas. La persona que le va a enseñar aperturas a nuestro programa podría ser otro actor, al que podemos llamar "maestro". Una misma persona puede ser varios actores. Por ejemplo si alguien compra nuestro programa de ajedrez, a veces puede jugar y otras veces puede enseñarle aperturas. Es la misma persona, pero el papel que desempeña en cada caso es distinto.

  • Identificar casos de uso. Un caso de uso es algo que un actor quiera hacer con nuestro sistema. Por ejemplo, un caso de uso para un "jugador" es "jugar una partida". Está claro que el jugador quiere nuestro programa para jugar una partida de ajedrez. Otro posible caso de uso es "análisis de un tablero". El "jugador" pone las piezas en determinada posición y quiere que el ordenador le dé una lista de posibles movimientos, etc. En resumen, debemos obtener una lista de cosas que los actores van a querer hacer con nuestro sistema. Deben ser cosas grandes y no meternos en los detalles. "Mover una pieza" no sería un caso de uso, sino una parte de "jugar una partida". De aquí saldría un diagrama UML de casos de uso.
    • Detallar casos de uso. En un texto vamos poniendo varios puntos. En cada punto ponemos sentencias del estilo "el usuario hace tal cosa y el programa hace tal otra". Es decir, explicamos por escrito, desde el punto de vista del usuario, qué es lo que tiene que hacer y qué es lo que va a hacer el ordenador.

En el caso de uso se detalla una situación normal, sin fallos ni situaciones raras. Al final debería ponerse una pequeña lista con los posibles fallos o situaciones anormales.

Advertir que en ningún caso nos hemos metido a detallar cómo va a hacer algo nuestro programa, solamente qué es lo que va a hacer.
Siguiendo los esquemas UML, podemos incluso hacer por cada caso de uso un diagrama de secuencia en el que los objetos implicados son el actor (el "jugador") y nuestro programa, sin meternos dentro de él.
También en este paso podemos ir empezando a pensar en cómo van a ser las pantallas de la interfase de usuario, de nuestro programa.

DISEÑO PRELIMINAR

Aquí ya empezamos a pensar en cómo vamos a hacer las cosas.

En el diseño preliminar tratamos de establecer la arquitectura de nuestro programa. La arquitectura es un esquema de en qué módulos/paquetes vamos a dividir nuestro programa, qué librerías. Si el programa es suficientemente grande, quizás vaya en varios ejecutables, una arquitectura cliente/servidor, etc.

Viendo los casos de usos, deberíamos ver qué cosas podemos hacer comunes o como librerías aparte, que podamos reutilizar.

Dentro de estos paquetes, podemos ir pensando más subpaquetes, etc.

En este punto y con los casos de uso en general, debemos tener cuidado. Según una crítica generalizada a los casos de uso, estos llevan a un diseño funcional y no a uno orientado a objetos. Debemos tratar de pensar en objetos y almacenarlos juntos en la misma librería cuando estén muy relacionados entre sí, no en funciones. Por ello es buena idea tratar de agrupar las clases del diagrama de clases del negocio en paquetes y tratar de desarrollar la arquitectura a partir de ellas.

Es importante en este paso definir las interfaces y relaciones entre paquetes. Para ello puede servir de ayuda hacer los diagramas de secuencia de los casos de uso mostrando los actores, los paquetes y los mensajes entre ellos. Según vayan creciendo los diagramas de secuencia por aquello de ir entrando en detalles, podremos ir extrayendo subcasos de uso, como "mover pieza", "elegir color", etc.

DISEÑO DETALLADO

En el diseño detallado ya se entra a nivel de clases y métodos. Por cada paquete que hayamos extraído en el paso anterior y siguiendo siempre los casos de uso, debemos ir detallando las clases que vamos a implementar y los métodos que van a tener. Detallamos aun más los casos de uso y las interfaces de las clases.

En este punto pueden ser de ayuda los patrones de diseño. La gente que ha ido diseñando a lo largo de la historia, se ha encontrado con problemas (¿cómo hago que la clase A se entere que la clase B ha cambiado sin necesidad de que B vea a A?, ¿En qué clase pongo el método que suma las clases A y B? ¿Como me aseguro que de esta clase sólo se haga una instancia?, etc.)Algunos de dichos problemas salen con mucha frecuencia (como los indicados de ejemplo) y se han establecido soluciones "Standard", que funcionan bien. Dichas soluciones se llaman patrones. No está de más leer algo sobre patrones de diseño orientados a objetos para tener una lista de "soluciones" a aplicar.

Hay incluso patrones a nivel de arquitectura. Es bastante conocido, por ejemplo, el patrón separación modelo-vista. En nuestro caso "modelo" sería el conjunto de clases que juegan al ajedrez. "Vista" sería el conjunto de clases que "pintan" la partida en la pantalla. Hacer esa separación en dos módulos, hace que nuestro módulo de ajedrez sea reaprovechable, incluso si cambiamos de entorno de ventanas (de Windows a ms-dos o de ms-dos a unix). Eso sí, es imprescindible que sólo la "vista" vea al "modelo" y nunca al revés. Si lo hacemos al revés y queremos llevarnos nuestro "modelo" juego de ajedrez, tendremos que llevarnos también parte de la "vista".

IMPLEMENTACIÓN Y PRUEBAS

Pues a ello. Hay muchas cosas que se podrían contar aquí, pero no son de diseño.

De las pruebas podemos decir que hay que escribir los "casos de prueba". Básicamente son como la descripción de los casos de uso, pero indicando datos concretos que el operador va a introducir y qué resultados exactos debe dar nuestro programa.

DESARROLLO ITERATIVO E INCREMENTAL

En casi todas las metodologías que he leído, se habla de hacer el sistema en varias iteraciones. Es decir, hacer un poco de requisitos, un poco de análisis, un poco de diseño, un poco de codificación y pruebas y vuelta a empezar.

Hay varios motivos para realizar esto así:

  • No eternizarse en un paso. Por mucho análisis que hagamos, nunca estaremos seguros de haber acabado y siempre se nos ocurrirán más cosas. Ídem para el diseño. Siguiendo este método, nos fijaríamos unos plazos para cada cosa y haríamos lo siguiente:
    • Obtener los máximos requisitos posibles en el tiempo fijado. Ordenarlos y fijarnos en los más importantes.
    • Obtener los máximos casos de uso y actores posibles. Ordenarlos por importancia (más importantes para el usuario, más difíciles de implementar o que ayuden a definir lo máximo posible la arquitectura) y detallar sólo los primeros en la lista.
    • Obtener la arquitectura para esos primeros casos de uso.
    • Diseño detallado para esos primeros casos de uso, siempre con un plazo.
    • Codificar y probar.
    • Vuelta a empezar con los requisitos (¿han cambiado?, ¿hay nuevos?), los casos de uso (buscar más casos de uso, detallar los siguientes en importancia), etc.

Cada uno de estos pasos hay que detenerlo cuando creamos que tenemos algo que puede funcionar. No hay que tratar de dejarlo perfecto. Cada vez que pasemos al siguiente paso, encontraremos fallos en el paso anterior. Hay que ir arreglándolos de forma que al final todo quede coherente.

  • Ir haciendo versiones intermedias de nuestro programa. Cuando hayamos implementado varios casos de uso (que son los más importantes), podemos hacer una versión para enseñar al cliente. Es mejor que ponga las pegas y sugerencias ahora que no cuando ya lo hayamos terminado todo. Este punto es especialmente útil cuando el cliente no sabe muy bien qué es lo que quiere.

No hay comentarios:

Publicar un comentario