Descomposición Modular y Técnicas de Diseño en Ingeniería de Software

Objetivos Inmediatos del Diseño

Los objetivos inmediatos del diseño son la descomposición modular y la decisión sobre algoritmos y estructuras de datos fundamentales.

Descomposición Modular

Dependiendo de lo que se entienda por módulo, tenemos la siguiente clasificación:

  • Código fuente: Es el considerado como tal con mayor frecuencia, contiene el texto fuente escrito.
  • Tabla de datos: Se utiliza para tabular ciertos datos de inicialización experimentales o de difícil obtención.
  • Configuración: Agrupamos en un mismo módulo toda aquella información que permite configurar el entorno concreto de trabajo.
  • Otros: Un módulo sirve para agrupar ciertos elementos del sistema relacionados entre sí y que se pueden tratar de forma separada del resto.

Solo en casos excepcionales se sacrificará el objetivo de tener un sistema mantenible en aras de la velocidad de proceso o un menor tamaño de código.

Cualidades Mínimas de una Descomposición Modular para Cualquier Tipo de Metodología

Independencia funcional: Para que exista un módulo, debe realizar una función concreta o un conjunto de funciones afines, sin apenas ninguna relación con el resto de los módulos del sistema. A mayor independencia, mayor mantenibilidad y reutilización. Para medir la independencia funcional entre varios módulos, tenemos dos criterios: Acoplamiento y Cohesión.

  • Acoplamiento: Tenemos varios tipos que pueden ser fuerte, moderado, débil, y en ese orden son:
    • Acoplamiento por contenido (fuerte): Desde un módulo se pueden cambiar los datos locales e incluso código de otro módulo.
    • Acoplamiento Común (fuerte): Se emplea una zona común de datos a la que tienen acceso varios o todos los módulos del sistema.
    • Acoplamiento Externo (fuerte): Aquí la zona común está constituida por algún dispositivo externo al que están ligados todos los dispositivos.
    • Acoplamiento de control (moderado): Una señal o dato de control que se pasa desde un módulo A a otro B es lo que determina la línea de ejecución que se debe seguir dentro de B.
    • Acoplamiento por etiqueta (débil): Los módulos se intercambian además de los datos, la estructura completa de la que forman parte.
    • Acoplamiento de datos (el más débil): Los módulos solo se intercambian los datos.

El objetivo es conseguir el acoplamiento más débil posible.

  • Cohesión: El contenido de cada módulo ha de tener la mayor coherencia posible. Tenemos varios tipos que pueden ser baja, media, alta, y en ese orden son:
    • Cohesión coincidental (la más baja): Cualquier relación entre los elementos del módulo es pura coincidencia.
    • Cohesión lógica (baja): Se agrupan en un módulo elementos que realizan funciones similares desde un punto de vista del usuario.
    • Cohesión temporal (baja): Se agrupan en el mismo módulo elementos que se ejecutarán en el mismo momento.
    • Cohesión de comunicación (media): Todos los elementos del módulo trabajan con el mismo conjunto de datos de entrada o producen el mismo conjunto de datos de salida.
    • Cohesión secuencial (media): Todos los elementos del módulo trabajan de forma secuencial.
    • Cohesión funcional (la más alta con técnicas de diseño funcional descendente): Cada elemento está encargado de la realización de una función concreta y específica.
    • Cohesión abstraccional (la más alta con técnica basada en abstracciones y con técnica orientada a objetos): En diseño basado en abstracciones se logra al diseñar un módulo como tipo abstracto de datos, se asocia un cierto contenido con las correspondientes operaciones. En diseño orientado a objetos se logra al diseñar un módulo como una clase de objetos, se asocian unos ciertos atributos con los correspondientes métodos encargados de su manejo.

El objetivo es conseguir una cohesión alta, facilitando el mantenimiento y la reutilización.

Comprensibilidad: Aparte de la independencia funcional, en la comprensibilidad concurren otros factores como son:

  • Identificación: Elección adecuada del nombre del módulo.
  • Documentación: Deben ser aclarados todos los aspectos de diseño o implementación.
  • Simplicidad: Los algoritmos sencillos son los mejores.

Adaptabilidad: Además de tener independencia funcional y comprensibilidad, para que el diseño tenga adaptabilidad se deben cuidar otros factores que son:

  • Previsión: Los módulos que se prevén que puedan cambiarse se deben agrupar en módulos con un acoplamiento lo más débil posible con el resto de los módulos.
  • Accesibilidad: Para poder adaptar un sistema, debe ser sencillo acceder a todos los documentos de especificación, diseño e implementación. Esto requiere una organización minuciosa que se hará normalmente con herramientas CASE.
  • Consistencia: Cuando se modifican los programas fuente, se deben modificar todos los documentos implicados. Esto se puede hacer automáticamente con herramientas para el control de versiones y configuración. En los entornos orientados a objetos no existen estas herramientas, por lo que se debe imponer una disciplina férrea dentro de la biblioteca.

Técnicas de Diseño Funcional Descendente

La descomposición del sistema se hace desde un punto de vista funcional, se van descomponiendo la función del sistema en funciones más sencillas, las cuales se encomiendan a módulos separados.

  • Desarrollo por refinamiento progresivo: Es la programación estructurada, en la que se emplean estructuras de control claras y sencillas como secuencia, selección e iteración. Se plantea el programa como una operación global única para ir descomponiéndola en otras operaciones más sencillas. En la etapa de diseño solo nos quedamos en los primeros niveles de refinamiento.
  • Programación estructurada de Jackson (JSP): Es similar a la programación estructurada, la diferencia está en las recomendaciones para ir construyendo la estructura del programa, que debe hacerse similar en lo posible a las estructuras de entrada y salida. Los pasos de esta técnica son:
    • Analizar el entorno del problema y describir las estructuras de datos a procesar.
    • Construir la estructura del programa basada en las estructuras de datos.
    • Definir las tareas a realizar en términos de las operaciones elementales disponibles y situarlas en los módulos apropiados de la estructura del programa.
  • Diseño estructurado: La tarea de diseño consiste en pasar de los DFD a los diagramas de estructura. La dificultad reside en que hay que establecer una jerarquía entre los diferentes módulos que no se ve en los DFD. A veces se usa un módulo de coordinación para construir esta jerarquía, y hay que hacer dos análisis del flujo de datos global.
    • Análisis de flujo de transformación: Se identifica el flujo global de información desde los elementos de entrada al sistema, hasta los de salida. Los procesos se deslindan en tres regiones: flujo de entrada, de transformación y de salida. Se asignan módulos para las operaciones del diagrama y se añaden módulos de coordinación que realizan el control de acuerdo con la distribución del flujo de transformación.
    • Análisis del flujo de transacción: Se puede aplicar cuando el flujo de datos se puede descomponer en varias líneas separadas. El análisis consiste en identificar el centro de transacción del que salen las líneas de flujo y las regiones correspondientes a cada una de esas líneas o transacciones.

Técnicas de Diseño Basado en Abstracciones

  • Descomposición modular basada en abstracciones: Consiste en ampliar el lenguaje existente con nuevas operaciones y tipos de datos definidos por el usuario. Se dedican módulos separados para cada tipo abstracto de datos y cada función importante. Se puede aplicar:
    • De forma descendente: Es como el refinamiento progresivo, en cada paso la operación a refinar se define separadamente como abstracción funcional o como tipo abstracto de datos.
    • De forma ascendente: Se van ampliando primitivas existentes en el lenguaje de programación y librerías con nuevas operaciones y tipos de mayor nivel, más adecuados para el campo de aplicación que se está diseñando.
  • Método de Abbott:
    • Identificar en el texto de la descripción los tipos de datos como sustantivos, los atributos como sustantivos y a veces como adjetivos, las operaciones como verbos o como nombres de acciones.
    • Hacer dos listas, una con nombres y otra con verbos.
    • Reorganizar las listas extrayendo los posibles datos y asociándoles sus atributos y operaciones, además de eliminar los sinónimos y añadir los elementos implícitos en la descripción.

Para obtener el diseño, asignamos un módulo a cada abstracción de datos o grupo de abstracciones relacionadas entre sí. El módulo puede corresponder a un dato encapsulado si solo se maneja un dato de ese tipo en todo el programa. Este método se puede usar tanto en diseño basado en abstracciones como en diseño orientado a objetos.

Técnicas de Diseño Orientadas a Objetos

El diseño orientado a objetos es similar al diseño basado en abstracciones, solo que añadiendo la herencia y el polimorfismo. Cada módulo contendrá la descripción de una clase de objetos o de varias relacionadas entre sí. Además del diagrama modular, nos apoyamos en diagramas ampliados del modelo de datos, como los diagramas de estructura.

  • Diseño orientado a objetos: Se basa en:
    • Estudiar el problema, reformulando las especificaciones para hacerlas más precisas.
    • Desarrollar una solución en líneas generales.
    • Formalizar esto en términos de clases de objetos y sus relaciones de la siguiente manera:
      • Identificar los objetos (o clases), sus atributos y componentes.
      • Identificar las operaciones sobre los objetos, asociarlas a la clase u objeto adecuado.
      • Aplicar herencia donde sea conveniente.
      • Describir cada operación en función de las otras y subsanar posibles omisiones.
    • Establecer la estructura modular: Asignando clases y objetos a módulos. Como resultado de esta etapa se obtiene el diagrama de estructura del sistema.

Técnicas de Diseño de Datos

En la organización de la base de datos se pueden ver tres niveles:

  • Nivel Externo: Corresponde a la visión del usuario.
  • Nivel Conceptual: Establece una organización lógica de los datos, a través de un diagrama de modelo de datos, bien E-R, bien diagrama de Modelo de objetos.
  • Nivel Físico: Organiza los datos según los esquemas del gestor de base de datos, si es una base de datos relacional serían tablas.

Del nivel Externo al conceptual se hace en el análisis. Del nivel conceptual al físico se hace en el diseño.

Diseño de Bases de Datos Relacionales

En el modelo relacional, la eficiencia se ve desde dos puntos de vista: formas normales para evitar las redundancias, índices para mejorar la velocidad de acceso a los datos.

  • Formas normales:
    • 1ª forma normal: Si la información asociada a cada una de las columnas es un valor único y no una colección de valores de número variable.
    • 2ª forma normal: Si está en 1ª forma normal y además hay una clave primaria que distingue cada fila y cada casilla que no sea de la clave primaria depende de toda la clave primaria.
    • 3ª forma normal: Si está en 2ª forma normal y además el valor de cada columna que no es clave primaria depende directamente de la clave primaria, esto es, no hay dependencias entre columnas que no son clave primaria.
  • Diseño de las entidades: Cada clase de entidad es una tabla, cada elemento de esa clase es una fila, cada atributo de esa entidad es una columna. El número o código de referencia, si se usa, sirve como clave primaria.

Tratamiento de las Relaciones de Asociación

En el modelo de objetos se tienen dos tipos especiales de relación: las de composición o agregación y las de herencia o especialización. Las demás son las de asociación. La técnica general válida para todas las cardinalidades es traducir la relación a una tabla conteniendo referencias a las tablas de las entidades relacionadas, así como los atributos de la relación si los hay.

  • Si la cardinalidad es 1-N: Se incluyen los datos de la relación en la misma tabla de una de las entidades relacionadas.
  • Si la cardinalidad es 1-1: Se pueden fundir las tablas de las dos entidades en una sola.

Tratamiento de las Relaciones de Composición

La cardinalidad del lado del objeto compuesto es casi siempre 1. Se aplican los mismos criterios anteriores.

Tratamiento de la Herencia

Cuando una clase tiene varias subclases, hay tres formas de almacenar en tablas la información de las entidades.

  1. Se usa una tabla para la superclase, con los atributos comunes heredados por las subclases, más una tabla por cada subclase con sus atributos específicos.
  2. Se repiten los atributos comunes en las tablas de cada subclase, por lo que desaparece la tabla de la superclase.
  3. Se amplía la tabla de la superclase con todos los atributos de cada una de las subclases, prescindiendo de las tablas de cada subclase.
  • Diseño de índices: Permiten acceder rápidamente a un dato concreto, a costa de aumentar el espacio de almacenamiento y el tiempo de almacenamiento de nuevos datos y la modificación del valor de un atributo indexado. Si hay que acceder a datos a través de sus relaciones con otros, es conveniente mantener índices sobre las claves primarias y columnas de referencia de las entidades relacionadas.

Diseño de Bases de Datos de Objetos

Hay una mayor variedad de estructuras disponibles, pero distintas en cada caso. Podemos ver dos enfoques en el diseño:

  • : Cuando la base de datos de objetos permite usar una gran variedad de estructuras. El sistema de gestión de base de datos aporta como complemento la persistencia de los datos.
  • : No existe esa variedad de estructuras y la base de datos de objetos es análoga a una base de datos relacional. El sistema de gestión de base de datos aporta la existencia implícita de identificadores de objetos, que hacen innecesarias las columnas explícitas de códigos o números de referencia.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.