miércoles, 9 de noviembre de 2011

Análisis y diseño estructurado

DEFINICIONES

Análisis
El análisis estructurado, como todos los demás métodos de análisis de requisitos, es una actividad de construcción de modelos. Mediante una notación que es única de este método, se crean modelos que reflejan el flujo y el contenido de la información (datos y control); se parte el sistema funcionalmente y, según los distintos comportamientos, se establece la esencia de lo que se debe construir.
La tarea del análisis de sistemas, conlleva más que sólo realizar análisis de requisitos, pero es en eso donde se focalizará la discusión.
Una de las principales labores del analista es descubrir detalles y documentar la política de un negocio que pudiera existir sólo en forma implícita, "transmitidas de generación en generación" por los usuarios, nunca documentadas formalmente. El analista debe distinguir entre síntomas, problemas del usuario y causas. Con sus conocimientos de la tecnología de los computadores, el analista debe ayudar al usuario a explorar aplicaciones novedosas y más útiles de éstos así como nuevas formas de hacer negocios. Aunque muchos de los sistemas antiguos sólo se limitaban a perpetuar el negocio original del usuario, pero a velocidades electrónicas, hoy en día los analistas se enfrentan al desafío de ayudar al usuario a encontrar productos y mercados radicalmente innovadores, con la ayuda del computador.

Diseño
El diseño de software es un proceso mediante el que se traducen los requisitos en una representación del software. Inicialmente, la representación describe una visión holística del software. Posteriores refinamientos conducen a una representación de diseño que se acerca mucho al código fuente.

En el diseño se realizan dos pasos. El diseño preliminar se centra en la transformación de los requisitos en los datos y arquitectura del software. El diseño detallado se ocupa del refinamiento de la representación arquitectónica que lleva a una estructura de datos detallada y a las representaciones algorítmicas del software.

Dentro del contexto de los diseños preliminar y detallado, se llevan a cabo varias actividades de diseño diferentes. Además del diseño de datos, del diseño arquitectónico y del diseño procedimental, muchas aplicaciones requieren de un diseño de la interfaz. El diseño de la interfaz establece la disposición y los mecanismos para la interacción hombre máquina (no cubierto por las herramientas del diseño estructurado).

FUNDAMENTOS DEL ANALISIS Y DISEÑO

Abstracción
Cuando se considera una solución modular para cualquier problema, pueden formularse muchos niveles de abstracción. En el nivel superior de abstracción, se establece una solución en términos amplios, usando el lenguaje del entorno del problema. En los niveles inferiores de abstracción se toma una orientación más procedimental. La terminología orientada al problema se acompaña con una terminología orientada a la implantación, en un esfuerzo para establecer una solución. Por último, en el nivel más bajo de abstracción, se establece la solución de forma que pueda implementarse directamente.

Refinamiento
El refinamiento sucesivo es una primera estrategia de diseño descendente (propuesta por Niklaus Wirth). Un programa se desarrolla en niveles sucesivos de refinamiento de los detalles procedimentales. Se desarrolla una jerarquía descomponiendo una declaración macroscópica de una función en forma sucesiva hasta que se llega a las sentencias del lenguaje de programación. Cada paso de refinamiento implica algunas decisiones de diseño. Es importante que el programador sea consciente de sus decisiones y de la existencia de soluciones alternativas.

Modularidad
Se ha dicho que modularidad es el atributo individual del software que permite a un programa ser intelectualmente manejable. El software monolítico (compuesto por sólo un módulo) no puede ser fácilmente abarcado por un lector. El número de caminos de control, la expansión de referencias, el número de variables y la complejidad global podrían hacer imposible su correcta comprensión. La modularidad se deriva naturalmente de un principio elemental para manejar la complejidad: divide y vencerás.

Diseño Modular Efectivo
La calidad del diseño debe ser una meta para el diseñador. El diseño estructurado ofrece guías para apoyar al diseñador a determinar módulos, y sus interconexiones, que mejor realizarán los requerimientos especificados por el analista. Las dos reglas más importantes son las referentes al acoplamiento y la cohesión.

Cohesión
Grado en el cuál los componentes de un módulo (típicamente las instrucciones individuales que lo conforman) son necesarios y suficientes para llevar a cabo una sola función bien definida. En la práctica, esto significa que el diseñador debe asegurarse de no fragmentar los procesos esenciales en módulos, y también debe asegurarse de no juntar procesos no relacionados en módulos sin sentido. Los mejores módulos son aquellos que son funcionalmente cohesivos (es decir, módulos en los cuales cada instrucción es necesaria para poder llevar a cabo una tarea bien definida). Los peores módulos son los que son coincidentalmente cohesivos (es decir, donde sus instrucciones no tienen una relación significativa entre uno y otro).

Los grados de cohesión, de menor a mayor son:
a) Cohesión Coincidental. No existe una relación significativa entre los elementos del módulo.
b) Cohesión Lógica. La relación entre los elementos del módulo está basada en obtener ventajas en el procesamiento, por ejemplo, todos manipulan el mismo dato. Normalmente esto implica tener un código truculento o compartido, que degrada los propósitos de un buen diseño.
c) Cohesión Temporal. Los elementos del módulo constituyen un conjunto que se ejecuta secuencialmente en un punto fijo en el tiempo. Aunque tiende, a veces, a confundirse con la cohesión lógica, la diferencia está en que este tipo de módulo s más simple y se ejecuta sin la intervención de otras aplicaciones.
d) Cohesión Comunicacional. Los elementos del módulo hacen referencia al mismo conjunto de datos. Aquí se presenta un grado "aceptable" de cohesión.
e) Cohesión Secuencial. Implica que la salida de un elemento es la entrada para el próximo.
f) Cohesión Funcional. Aquí, todos los elementos del módulo están orientados a la realización de una función única.

Acoplamiento
Grado en el cuál los módulos se interconectan o se relacionan entre ellos. Entre más fuerte sea el acoplamiento entre módulos en un sistema, más difícil es implantarlo y mantenerlo, pues entonces se necesitará un estudio cuidadoso para la modificación de algún módulo o módulos. En la práctica, esto significa que cada módulo debe tener interfaces sencillas y limpias con otros, y que se debe compartir un número mínimo de datos entre módulos. También significa que un módulo dado no debe modificar la lógica interna o los datos de algún otro módulo; lo que se conoce como una conexión patológica.

Tamaño del módulo
De ser posible, cada módulo debe ser lo suficientemente pequeño como para caber en una sola página ( o para que se pueda desplegar en una sola pantalla). Desde luego, a veces no es posible determinar qué tan grande va a ser un módulo hasta haberlo escrito, pero las actividades iniciales de diseño a menudo darán al diseñador una buena pista de que el módulo será grande o complejo. Si es así, debe subdividirse en uno o más niveles de submódulos.

Alcance del control
El número de subordinados inmediatos que un módulo administrador puede llamar se conoce como el alcance del control. Un módulo no debe poder llamar a más de una media docena de módulos de nivel inferior. La razón es evitar la complejidad: si el módulo tuviera, por ejemplo, que llamar a 25 módulos de nivel inferior, entonces seguramente contendrá tanta lógica compleja que nadie lo entenderá (un sin fin de if-then anidados). La solución es introducir un nivel intermedio de módulos administradores, como haría un administrador de una organización humana.

Alcance del efecto/alcance del control
Esta regla sugiere que cualquier módulo afectado por el resultado de alguna decisión debe ser subordinado (aunque no necesariamente un subordinado inmediato) del módulo que toma la decisión. Es un tanto análogo a la regla de administración que dice que cualquier empleado afectado por los resultados de la decisión de algún administrador (es decir, dentro del alcance de efecto de la decisión), debe estar dentro del alcance de control del administrador (es decir trabajando entre la jerarquía de personas que se reportan con el administrador). Violar esta regla en un ambiente de diseño estructurado usualmente lleva a un paso innecesario de banderas y condiciones (lo cual incrementa el acoplamiento entre módulos), la toma redundante de decisiones o (en el peor de los casos) conexiones patológicas entre módulos.

Parsimonia
Se refiere a la economía de recursos que se emplean para la obtención de un resultado. Esto es, sólo se debe realizar lo que se pide. Mientras mayor la parsimonia, mejor el diseño.

Manejo Autónomo de Errores
Los módulos deben tener la capacidad de manejar sus propias condiciones de error, tanto en la detección como en la corrección de los mismos. De no ser así, el manejo de banderas (flags) de control y la transmisión de datos erróneos a otros módulos aumentarán considerablemente el acoplamiento.

DIAGRAMAS DE ESTRUCTURA
A través de los diagramas de estructura se puede modelar el control del sistema, así como la descomposición de las funciones en forma jerárquica.

En un diagrama de estructura, los módulos son representados por rectángulos. Se representa la dependencia (jerárquica) entre módulos, las instancias de repetición y decisión así como el flujo de los datos de control y otros a través de las funciones. Los módulos del diagrama de estructura son los mismos que los que aparecen en los distintos niveles del DFD, vistos en otra dimensión.

Aunque el módulo padre de un diagrama de estructura o módulo raíz puede tener dos o n hijos en su segundo nivel de descomposición, se recomienda descomponer este módulo en 3 hijos, cada uno de ellos dará origen a una rama en el diagrama de estructura, es decir, cada uno de ellos a su vez podrá tener otros módulos hijos. Estas ramas son:
a) rama aferente: su objetivo es capturar u obtener la información proveniente generalmente del usuario.
b) rama de proceso: transforma la información capturada, es decir las entradas, en las salidas del sistema. rama eferente: su objetivo es entregar las salidas del sistema al usuario o al terminador que corresponda.
c) rama eferente: su objetivo es entregar las salidas del sistema al usuario o al terminador que corresponda.

ESTRATEGIAS DE DISEÑO
Ya se sabe cómo se puede representar la estructura modular del sistema, ahora se muestra como realizar esta representación utilizando como punto de partida los gráficos obtenidos mediante las técnicas de la fase de análisis. Esto significa que se debe hacer una especie de traducción entre diagramas. El paso de los Diagramas de Flujo de Datos (DFD) a los Diagramas de Estructura (DE) puede hacerse a partir de las siguientes estrategias:
· Análisis de transformación. A partir de un DFD con características de transformación (Flujo de Entrada, Centro de la transformación, Flujo de Salida).
· Análisis de transacción. Cuando en un DFD un dato determina la elección de uno o más flujos de información.

Se presenta a continuación de manera detallada cada una de estas estrategias, se debe tener en cuenta que se trata de estrategias y no de algoritmos, por lo tanto los resultados pueden no ser perfectos en una primera aproximación.

Análisis de transformación
Para el análisis de transformación se deben realizar los siguientes pasos:
1. Aislar el centro de transformación. Es la parte del DFD que contiene las funciones esenciales del sistema y es independiente de las características particulares de la entrada/salida. Los límites de flujo de llegada y salida están abiertos a interpretación.
2. Realizar el primer nivel de factorización. La estructura del programa debe representar una distribución descendente del control características particulares de la Entrada/Salida. Aparecerán tres módulos subordinados al módulo de control: (a) Módulo controlador del proceso de la información de llegada. (b) Módulo controlador del centro de transformación. (c) Módulo controlador del proceso de la información de salida.
3. Elaborar el segundo nivel de factorización. Se realiza mediante la conversión de las transformaciones de cada proceso de un DFD en los módulos correspondientes del diagrama de estructura. Se comienza en el centro de transformación y se va hacia afuera a lo largo de los caminos de llegada y salida.
4. Refinar la estructura del sistema utilizando medidas y heurísticas de diseño.

Análisis de transacción
El análisis de transacción se aplica cuando un DFD toma una forma en la que un dato determina la elección de uno o más flujos de información. Los pasos a seguir son:
1. Identificar el centro de transacción. Será el origen de una serie de caminos que fluyen radialmente. Cada camino, tanto de llegada como los de acción, debe evaluarse en función de sus características individuales.
2. Transformar el DFD en la estructura adecuada al proceso de transacciones. El flujo de transacciones se convierte en una estructura de programa formada por una bifurcación de entrada y una de salida.
3. Factorizar la estructura de cada camino de acción. La estructura de la bifurcación de entrada se desarrolla de la misma forma que el análisis de transformación. Cada camino del flujo de acción se convierte en una estructura que se corresponde con las características específicas del flujo (transformación, transacción). Cada camino de acción estudiado usa los pasos de diseño vistos anteriormente.
4. Refinar la estructura del sistema utilizando medidas y heurísticas de diseño.

EVALUACIÓN DEL DISEÑO
Para estimar si el diseño del sistema es todo lo correcto que se precisa para su funcionamiento, se utilizan dos unidades complementarias de medida:
· Acoplamiento, es el grado de interdependencia entre los módulos, depende del número de parámetros que se intercambian para su comunicación.
· Cohesión, es el grado en el que los componentes de un módulo son necesarios y suficientes para realizar una sola función bien definida.

Acoplamiento
En módulos con acoplamiento alto se debe considerar un módulo cuando se modifica el otro. El objetivo es conseguir un diseño con bajo acoplamiento. Interesa que la interdependencia entre módulos sea lo más baja posible, para conseguir que los problemas de cualquier módulo afecten lo menos posible al resto del sistema, esto redunda en un mejor funcionamiento del sistema, más fácil mantenimiento y reutilización.

Los principales factores que afectan al acoplamiento son:
· Conexión de información entre módulos.
· Información que pasa de un módulo a otro.
· Entrada y salida al módulo.
· Complejidad de la información que se transmite.

Existen varios niveles de acoplamiento, de mejor a peor:
· Acoplamiento Normal. En este acoplamiento se diferencian los siguientes tipos: (a) De datos, entre el módulo que llama y el llamado, debe establecerse al menos una comunicación básica. (b) Por estampado, si se pasan datos entre módulos con estructura de registro, no es deseable si el módulo que recibe el registro sólo necesita parte de los datos. (c) De control, cuando los datos de comunicación son flags de control, supone una ruptura en el principio de caja negra, ya que el módulo inferior tiene detalles de funcionamiento del superior, esto es malo si se cambia el módulo inferior.
· Acoplamiento Común. Se produce cuando más de dos módulos hacen referencia a un área común de datos. Puede dar problemas si los módulos acceden sin demasiado control a esa área común.
· Acoplamiento de contenido. Se da cuando un módulo cualquiera, accede a parte del código de otro rompiendo la jerarquía.

Cohesión
Es la medida de la fuerza o relación funcional de los elementos de un módulo, entendiendo por elementos a la sentencia o grupo de sentencias que lo componen, a las definiciones de datos o llamadas a otros módulos. Un módulo coherente sólo debe hacer (idealmente) una cosa. El objetivo es conseguir una alta cohesión, donde cada instrucción es necesaria para llevar a cabo una sola tarea.

Los distintos niveles de cohesión son de mejor a peor:
· Funcional. Un módulo con cohesión funcional contiene elementos que contribuyen a la realización de una, y sólo una, tarea funcional.
· Secuencial. Un módulo realiza varias tareas en secuencia, de modo que las entradas de cada tarea son las salidas de la anterior.
· Comunicacional. Un módulo realiza actividades paralelas usando los mismos datos de entrada y salida.
· Procedimental. Igual que la secuencial, pero con paso de controles.
· Temporal. Las actividades que realiza tienen un matiz temporal.
· Lógica. El módulo tiene algo así como partes dentro de sí mismo.
· Coincidente. El módulo que llama tiene conocimiento de la estructura interna del módulo al que llama.

Esta evaluación del diseño permite efectuar cambios importantes en el diseño, si se descubre errores de cierta importancia, es el momento de realizar un ajuste fino en el mismo.
Heurísticas del diseño
Son recomendaciones para mejorar la estructura del diseño y mejorar la modularidad. Se consideran las siguientes características:
· Tamaño del módulo, entre 10 y 100 sentencias.
· Ámbito de control, el ámbito de control de un módulo es todos los módulos que hay por debajo de él.
· Ámbito de efecto, cualquier módulo afectado por una decisión, debe ser subordinado del módulo que toma la decisión.

Corrección del diseño
Las reglas de oro para realizar un buen diseño son las siguientes:
· No utilizar variables globales.
· Evitar pasar parámetros, a menos que sea necesario.
· Reducir el número de parámetros que intercambian al máximo.
· No agrupar las líneas de código aleatoriamente, sino que deben ser agrupadas por funciones.
· Un módulo de un nivel inferior no debe llamar a otro de nivel superior de la misma rama del diagrama, puede dar lugar a bucles sin salida.

Definición de programas
Para la definición de programas deben agruparse todos los módulos que se han definido de manera funcional, para el efecto existen dos posturas dos posturas diferentes:
· Construir un programa por cada módulo.
· Agrupar los módulos en un programa, asociando cada uno de ellos a un párrafo.