Las etapas principales a realizar en cualquier ciclo de vida son:

Análisis: Construye un modelo de los requisitos . Diseño: A partir del modelo de análisis se deducen las estructuras de datos, la estructura en la que descompone el sistema y la interfaz de usuario. Codificación: Construye el sistema. La salida de esta fase es código ejecutable. Pruebas: Se comprueba que se cumplen criterios de corrección y calidad. Mantenimiento: En esta fase, que tiene lugar después de la entrega se asegura que el sistema siga funcionando y adaptándose a nuevos requisitos.

Las etapas constan de tareas. La documentación es una tarea importante que se realiza en todas las etapas.

Algunos autores dividen la fase del diseño en dos partes: Diseño global o arquitectónico y diseño detallado

En el primero se transforman los requisitos en una arquitectura de alto nivel, se definen las pruebas que debe satisfacer el sistema en su conjunto, se esboza la documentación y se planifica la integración. En el detallado para cada módulo se refina el diseño, se definen los requisitos del módulo y su documentación.

Las formas de organizar y estructurar la secuencia de ejecución de las tareas en las diferentes fases de cada uno de los métodos puede dar lugar a un tipo de ciclo de vida diferente

ciclo de vida cascada: Las formas de organizar y estructurar la secuencia de ejecución de las tareas en las diferentes fases de cada uno de los métodos puede dar lugar a un tipo de ciclo de vida diferente—analisis-diseño-codificacion-pruebas-mantenimiento

descripcion: admite la posibilidad de hacer iteraciones, es decir, durante las modificaciones que se hacen en el mantenimiento se puede ver por ejemplo la necesidad de cambiar algo en el diseño, lo cual significa que se harán los cambios necesarios en la codificación y se tendrán que realizar de nuevo las pruebas, es decir, si se tiene que volver a una de las etapas anteriores al mantenimiento hay que recorrer de nuevo el resto de las etapas.



Trabaja en base a documentos, es decir, la entrada y la salida de cada fase es un tipo de documento específico. Los documentos son:

  • Análisis: Toma como entrada una descripción en lenguaje natural de lo que quiere el cliente. Produce el S.R.D. (Software Requirements Document).
  • Diseño: Su entrada es el S.R.D. Produce el S.D.D. (Software Design Document)
  • Codificación: A partir del S.D.D. produce módulos. En esta fase se hacen también pruebas de unidad.
  • Pruebas: A partir de los módulos probados se realiza la integración y pruebas de todo el sistema. El resultado de las pruebas es el producto final listo para entregar.

Ventajas : La planificación es sencilla. – La calidad del producto resultante es alta. – Permite trabajar con personal poco cualificado.

Inconvenientes: Si se han cometido errores en una fase es difícil volver atrás.- No se tienen indicadores fiables del progreso del trabajo (síndrome del 90%).- Es comparativamente más lento que los demás y el coste es mayor también.

Ciclo de vida V: Propuesto por Alan Davis, tiene las mismas fases que el anterior pero se considera el nivel de abstracción de cada una. Una fase además de utilizarse como entrada para la siguiente, sirve para validar o verificar otras fases posteriores

En este caso sin embargo, se permite un solapamiento entre fases. Por ejemplo, sin tener terminado del todo el diseño se comienza a implementar. El nombre “sashimi” deriva del modo del estilo de presentación de rodajas de pescado crudo en Japón. Una ventaja de este modelo es que no necesita generar tanta documentación como el ciclo de vida en cascada puro debido a la continuidad del mismo personal entre fases. Los problemas planteados son: Es aún más difícil controlar el progreso del proyecto debido a que los finales de fase ya no son un punto de referencia claro. – Al hacer cosas en paralelo si hay problemas de comunicación pueden surgir inconsistencias.



Ciclo de vida en cascada con subproyectos: Si se ha llegado al diseño arquitectónico, se comprueba que el sistema se divide en varios subsistemas independientes entre sí, sería razonable suponer que a partir de ese punto cada uno se puede desarrollar por separado y en consecuencia en paralelo con los demás. Ciclo de vida en cascada incremental: se va creando el sistema añadiendo pequeñas funcionalidades. Cada uno de los pequeños incrementos es parecido a lo que ocurre dentro de la fase de mantenimiento. La ventaja de este método es que no es necesario tener todos los requisitos en un principio. El inconveniente es que los errores en la detección de requisitos se encuentran tarde. Para evitar este problema se puede hacer un desarrollo iterativo durante las fases de análisis y diseño global. Esto consistiría en: Preguntar al usuario. – Hacer el diseño global que se desprende del punto 1. – Hacer un prototipo de interfaz de usuario, entrevistas con los usuarios, etc y volver con ello al punto 1 para identificar más requisitos o corregir malentendidos. Modelo de ciclo de vida en espiral: Consiste en una serie de ciclos que se repiten. Cada uno tiene las mismas fases y cuando termina da un producto ampliado con respecto al ciclo anterior. En este sentido es parecido al modelo incremental, la diferencia importante es que tiene en cuenta el concepto de riesgo. Un riesgo puede ser muchas cosas: requisitos no comprendidos, mal diseño, errores en la implementación, etc. Boehm recomienda recopilar la siguiente lista de informaciones: Objetivos: Se hacen entrevistas a los clientes, se les hace rellenar cuestionarios, etc. Alternativas: Son las diferentes formas posibles de conseguir los objetivos. Se consideran desde dos puntos de vista – Características del producto. – Formas de gestionar el proyecto. estricciones: Desde el punto de vista del producto: Interfaces de tal o cual manera, rendimiento, etc. – Desde el punto de vista organizativo: Coste, tiempo, personal, etc. Riesgos: Lista de riesgos identificados. Resolución de riesgos: La técnica más usada es la construcción de prototipos. Resultados: Son lo que realmente ha ocurrido después de la resolución de riesgos. Planes: Lo que se va a hacer en la siguiente fase. Compromiso: Decisiones de gestión sobre como continuar.


Ventajas: No necesita una definición completa de los requisitos para empezar a funcionar. – Al entregar productos desde el final de la primera iteración es más fácil validar los requisitos.

Inconvenientes: Es difícil evaluar los riesgos. – Necesita de la participación continua por parte del cliente. – Cuando se subcontrata hay que producir previamente una especificación completa de lo que se necesita, y esto lleva tiempo.

Ciclos de vida orientados a objetos: Los tipos de ciclos de vida que se han visto hasta ahora son relativos al análisis y diseño estructurados, pero los objetos tienen una particularidad, y es que están basados en componentes que se relacionan entre ellos a través de interfaces, o lo que es lo mismo, son mas modulares y por lo tanto el trabajo se puede dividir en un conjunto de miniproyectos. Además, hoy en día la tendencia es a reducir los riesgos, y en este sentido, el ciclo de vida en cascada no proporciona muchas facilidades. Debido a todo esto, el ciclo de vida típico en una metodología de diseño orientado a objetos es iterativo e incremental.

Modelo fuente: Fue creado por Henderson-Sellers y Edwards en 1990. Es un tipo de ciclo de vida pensado para la orientación a objetos y posiblemente el más seguido. Un proyecto se divide en las fases: Planificación del negocioConstrucción: Es la más importante y se divide a su vez en otras cinco actividades +Planificación +Investigación +Especificación +Implementación +Revisión Entrega

La primera y la tercera fase son independientes de la metodología de desarrollo orientado a objetos. Además de las tres fases, existen dos periodos:Crecimiento: Es el tiempo durante el cual se construye el sistema – Madurez: Es el periodo de mantenimiento del producto. Cada mejora se planifica igual que el periodo anterior, es decir, con las fases de Planificación del negocio, Construcción y Entrega. – Cada clase puede tener un ciclo de vida sólo para ella debido a que cada una puede estar en una fase diferente en un momento cualquiera. La ventaja es que permite un desarrollo solapado e iterativo. En la figura se muestra un esquema de este tipo de ciclo de vida.



Patrones de diseño: Un patrón de diseño es: una solución estándar para un problema común de programación – una técnica para flexibilizar el código haciéndolo satisfacer ciertos criterios – un proyecto o estructura de implementación que logra una finalidad determinada – un lenguaje de programación de alto nivel – una manera más práctica de describir ciertos aspectos de la organización de un programa – conexiones entre componentes de programas – la forma de un diagrama de objeto o de un modelo de objeto.

Ejemplos: Presentamos algunos ejemplos de patrones de diseño que ya conocen. A cada diseño de proyecto le sigue el problema que trata de resolver, la solución que aporta y las posibles desventajas asociadas. Un desarrollador debe buscar un equilibrio entre las ventajas y las desventajas a la hora de decidir que patrón utilizar. Lo normal es, como observará a menudo en la ciencia computacional y en otros campos, buscar el balance entre flexibilidad y rendimiento.

Encapsulación: Problema: los campos externos pueden ser manipulados directamente a partir del código externo, lo que conduce a violaciones del invariante de representación o a dependencias indeseables que impiden modificaciones en la implementación. Solución: esconda algunos componentes, permitiendo sólo accesos estilizados al objeto. Desventajas: la interfaz no puede, eficientemente, facilitar todas las operaciones deseadas. El acceso indirecto puede reducir el rendimiento.

Subclase (herencia):Problema: abstracciones similares poseen miembros similares (campos y métodos). Esta repetición es tediosa, propensa a errores y un quebradero de cabeza durante el mantenimiento. Solución: herede miembros por defecto de una superclase, seleccione la implementación correcta a través de resoluciones sobre qué implementación debe ser ejecutada. Desventajas: el código para una clase está muy dividido, con lo que, potencialmente, se reduce la comprensión. La introducción de resoluciones en tiempo de ejecución introduce overhead (procesamiento extra).



Ejemplo Subclase: Los tres pilares de la Programación Orientada a Objetos Según se dice por ahí, cualquier lenguaje basado en objetos debe cumplir estos tres requisitos:Herencia – Encapsulación – Polimorfismo

Herencia: Esto es lo que la documentación de Visual Studio .NET nos dice de la herencia: Una relación de herencia es una relación en la que un tipo (el tipo derivado) se deriva de otro (el tipo base), de tal forma que el espacio de declaración del tipo derivado contiene implícitamente todos los miembros de tipo no constructor del tipo base.  “La herencia es la capacidad de una clase de obtener la interfaz y comportamiento de una clase existente.”

Iteración: Problema: los clientes que desean acceder a todos los miembros de una colección deben realizar un transversal especializado para cada estructura de datos, lo que introduce dependencias indeseables que impiden la ampliación del código a otras colecciones. Solución: las implementaciones, realizadas con conocimiento de la representación, realizan transversales y registran el proceso de iteración. El cliente recibe los resultados a través de una interfaz estándar.Desventajas: la implementación fija la orden de iteración, esto es, no está controlada en absoluto por el cliente.

Excepciones: Problema: los problemas que ocurren en una parte del código normalmente han de ser manipulados en otro lugar. El código no debe desordenarse con rutinas de manipulación de error, ni con valores de retorno para identificación de errores. Solución: introducir estructuras de lenguaje para arrojar e interceptar excepciones. Desventajas: es posible que el código pueda continuar aún desordenado. Puede ser difícil saber dónde será gestionada una excepción. Tal vez induzca a los programadores a utilizar excepciones para controlar el flujo normal de ejecución, que es confuso y por lo general ineficaz.

1.2 Cuando (no) utilizar patrones de diseño: La primera regla de los patrones de diseño coincide con la primera regla de la optimización: retrasar. Del mismo modo que no es aconsejable optimizar prematuramente, no se deben utilizar patrones de diseño antes de tiempo.


1.3 ¿Por qué preocuparse? : Si es usted un programador o un diseñador brillante, o dispone de mucho tiempo para acumular experiencia, tal vez pueda hallar o inventar muchos patrones de diseño. Sin embargo, esta no es una manera eficaz de utilizar su tiempo. Un patrón de diseño es el trabajo de una persona que ya se encontró con el problema anteriormente, intentó muchas soluciones posibles, y escogió y describió una de las mejores. Y esto es algo de lo que debería aprovecharse.2. Patrones de creación: 2.1 Fábricas: Suponga que está escribiendo una clase para representar carreras de bicicletas. Una carrera se compone de muchas bicicletas (entre otros objetos, quizás).

2.1.1 Método de fabrica: Un método de fábrica es el que fabrica objetos de un tipo determinado.

2.1.2 Objeto de fábrica: Si existen muchos objetos para construir, la inclusión de los métodos de fábrica puede inflar el código haciéndolo difícil de modificar. Las subclases no pueden compartir fácilmente el mismo método de fábrica. – Un objeto de fábrica es un objeto que comprende métodos de fábrica.

2.1.3 El patrón prototipo: El patrón prototipo ofrece otra manera de construir los objetos de los tipos arbitrarios. En lugar de pasar un objeto BicycleFactory, un objeto Bicycle es recibido como argumento. Su método clone es invocado para crear nuevos objetos Bicycle; estamos construyendo copias del objeto ofrecido.

2.2 El patrón Sharing: Muchos otros patrones de diseño están relacionados con la creación de objetos en el sentido de que influyen sobre los constructores (y necesitan utilizar fábricas) y están relacionados con la estructura en el sentido de que especifican patrones sharing entre varios objetos.

2.2.1 El patrón singular: El patrón singular garantiza que, en todo momento, sólo existe un objeto de una clase particular.

2.2.2 El patrón Interning: El patrón de diseño Interning reutiliza objetos inexistentes en vez de crear nuevos.

2.2.3 Flyweight: El patrón Flyweight es una generalización del patrón Interning. El patrón Interning es aplicable sólo cuando un objeto es completamente inmutable.

Patrón de Diseño: Elementos esenciales de un patrón: Nombre – Problema – Solución – Consecuencia

Descripción de los patrones de diseño: Nombre del Patrón y Clasificación: Propósito También conocido como: Motivación – Aplicabilidad – Estructura – Participantes – Colaboraciones – Consecuencias – Implementación – Código de Ejemplo – Usos conocidos – Patrones relacionados.

Algunos patrones de diseño: Delegado (Delegate), Compuesto (Composite), Decorador (Decorator), Mediador (Mediator), Iterador (Iterator), Observador (Observer), Modelo-vista-controlador (Model-View-Controller), Factoria, Data Access Object (DAO).

Patrón “delegado” – Delegate: La herencia es útil para modelar relaciones de tipo es-un o es-una, ya que estos tipos de relaciones son de naturaleza estática. Sin embargo, relaciones de tipo es-un-rol-ejecutado-por son mal modeladas con herencia.

Un objeto receptor delega operaciones en su delegado. Presente en muchos patrones: State, Strategy, Visitor…. Un ejemplo: supongamos que un objeto debe ordenar una estructura de datos. Puede delegar en otro objeto el método de comparación. En Java tenemos un caso: la clase Collections tiene el método estático sort(); desde este método se delega en un comparador para establecer el orden.

Patrón “compuesto” – Composite: Crear jerarquías parte/todo de tal forma que los clientes manejan a los objetos primitivos y compuestos de forma uniforme.

 

Otro ejemplo puede ser un activo financiero (un fondo de inversión) que es un compuesto de otros activos financieros simples (valores o acciones).

Los clientes pueden tratar objetos primitivos y compuestos de modo uniforme y es fácil añadir nuevos tipos de componentes.

Patrón “decorador: Imaginemos que tenemos un editor de texto básico y queremos añadirle nuevas funcionalidades, como un scroll o un borde. Una solución podría ser crear subclases para un editor con scroll, sin scroll, con scroll y con borde, etc. Evidentemente esta no es una buena solución, ya que acabamos con una jungla de clases y subclases.

Con este patrón tratamos de evitar este efecto de herencia-jungla, ya que asignamos dinámicamente nuevas responsabilidades a un objeto. Es una alternativa más flexible a crear subclases para extender la funcionalidad de una clase. De esta forma añadimos atributos o comportamiento adicional a un objeto concreto, no a una clase.

Patrón “intermediario” – mediator: Supongamos una ventana con numerosos componentes gráficos (widgets) que tienen fuertes dependencias entre si. Por ejemplo, reglas del tipo “si el campo de edición E2 está relleno, entonces inhabilito el botón B1 y el campo de edición E3”.

El mediador o intermediario encapsula la forma en que interaccionan un conjunto de objetos (“colegas”). Es el especialista que define las interdependencias entre ellos. Favorece un bajo acoplamiento, ya que evita que los objetos se referencien unos a otros de forma explícita. Permite variar la interacción sin tocar los colegas, por tanto favorece la reutilización.

Ventajas: Evita crear subclases, Desacopla a los colegas, Simplifica los protocolos entre las clases, Abstrae el cómo cooperan los objetos, Centraliza el control en el mediador: clase difícil de mantener


Para la implementación: No hay necesidad de definir una clase abstracta Mediator si los colegas trabajan con un único mediador, Los colegas deben comunicarse con el mediador cuando un evento de interés ocurre, esta comunicación puede hacerse con un Observer o un interfaz de notificación (ViewManager de Smalltalk-V), Cada colega tiene una referencia al mediador y de esta manera le pueden informar de los cambios realizados. Por ejemplo, una lista informa al mediador del cambio de item seleccionado; el mediador puede responder solicitando el texto seleccionado en la lista y mandándolo a un campo de texto. Ver el siguiente diagrama:

Patrón “iterador” : Supongamos que tenemos un contenedor (por ejemplo, un vector) y queremos tener una forma de acceder a los elementos sin mostrar los detalles. Un objeto contenedor debe permitir una forma de recorrer sus elementos sin exponer su estructura interna, es decir, separar el contenedor de la forma de recorrer sus elementos. Con este patrón tenemos la ventaja de simplificar la interfaz de un contenedor, ya que no contiene los métodos de recorrerlo.

Patrón “observador”:   Definir una dependencia de 1:n de forma que cuando el objeto 1 cambie su estado, los n objetos sean avisados y se actualicen automáticamente. Supongamos que tenemos un o unos objetos dependientes de otro. Por ejemplo, supongamos que una ventana o applet depende de los componentes gráficos que reciben eventos (clic en botón, etc.). Otro caso, típico del patrón, es tener diversas vistas de una fuente de datos, de tal forma que si cambia la fuente, entonces las vistas se actualicen automáticamente.



El observador no es un mediador entre los sujetos (objetos que cambian de estado) y los objetos dependientes, ya que el mismo es un objeto dependiente. El observador recibe la orden de actualizarse por parte del sujeto “dominante”

Una extensión natural de este patrón es hacer mezcla del patrón mediador y del patrón observador, de tal forma que los avisos de cambios que mandamos al observador sean notificados a otros objetos dependientes. El observador recibe un mensaje de cambio de estado y notifica a los objetos dependientes que se actualicen. Dicho de otra forma, cuando las relaciones de dependencia entre Subject y Observer son complicadas conviene encapsular la semántica de actualización en una clase ManejadorCambio(Mediador).