parent nodes: WikiOtros
Apuntes de Diseño del Software
Válidos para cualquier lenguaje orientado a objetos
Author: César TM
Date: 07/11/2011
Source: Internet
MVC
Desacoplamiento
Contenido
Descomponer un programa en partes.
Análizar del problema del acoplamiento entre partes.
Mostrar métodos para simplificarlo.
Las especificaciones son en sí mismas elementos de diseño.
Las especificaciones resultan esenciales para el desacoplamiento y, por lo tanto, para el diseño de alta calidad.
Diferenciar entre los términos usa y depende
Construir y analizar diagramas de dependencia
Descomposición
Un programa se construye a partir de un conjunto de partes.
Hay que descubrir qué partes integran ese conjunto y qué relación guardan entre ellas.
Resulta más fácil conseguir que una parte pequeña, y no una grande, funcione correctamente.
Ventajas se derivan de la división de un programa en partes pequeñas:
División del trabajo.
Reusabilidad.
Análisis modular.
Cambio localizado.
Las partes de un programa son descripciones
El desarrollo de software se centra en producir, analizar y ejecutar descripciones.
No todas las partes del software son ejecutables
Las especificaciones (documentación) también son partes del software
Diseño descendente "top down" (Este sistema fracasa rotundamente)
Consiste en aplicar de manera recursiva:
Si la parte que se quiere construir se halla ya disponible (como, por ejemplo, las instrucciones de un aparato), el proceso ya está terminado.
Si la parte no está disponible, se divide en subpartes, que se desarrollan y combinan entre sí.
La división en subpartes se llevaba a cabo mediante la “descomposición funcional”: se piensa en la función que debe tener la parte y se desglosa esa función en pasos más pequeños.
Este sistema fracasa rotundamente:
la primera descomposición que se hace es la más decisiva
no se descubre si se ha hecho correctamente hasta que no se llega al nivel más bajo
no se puede testear una descomposición en dos partes que no se han implementado y unido
al encontrar un error hay que deshacer lo que ya está implementado
es una estrategia arriesgada, costosa y totalmente inadecuada.
En la práctica, lo que normalmente ocurre es que la descomposición es imprecisa, y se va refinando a medida que se hace el ensamblado, recurriendo a trucos para que las partes encajen unas con otras. Las partes quedan acopladas entre sí de forma muy extensa, hasta tal punto que resulta imposible introducir la más mínima variación en una de ellas sin cambiar las otras. En el peor de los casos, las partes no encajarán en absoluto. Por último, ninguna de las características del diseño top-down favorece la reusabilidad del código.
Una estrategia mejor
desarrollar una estructura de sistema de múltiples partes a partir de niveles similares de abstracción.
perfeccionar la descripción de cada parte de una sola vez
analizar si las partes encajan
analizar si consiguen la funcionalidad deseada antes de empezar a implementar nada
Es más conveniente organizar un sistema en torno a datos que en torno a funciones.
Lo más importante a la hora de descomponer en partes es el modo en que esas partes están acopladas unas con otras.
Minimizar el acoplamiento (desacoplar las partes) para trabajar en cada una de ellas por separado
Relaciones de dependencia
Diagrama de casos de uso
Se dice que una parte A usa una parte B cuando A se refiere a B de tal manera que el significado de A depende del significado de B.
Cuando A y B son código ejecutable, el significado de A es su comportamiento cuando se ejecuta, de modo que A usa a B cuando el comportamiento de A depende del comportamiento de B.
(...) ver documento lecture-02.pdf
¿Qué podemos hacer con los diagramas de casos de uso?
Argumentación Para verificar que una parte es correcta hay que comprobar esa parte, las partes que usa, las partes que usan a esta y así sucesivamente. Todas las partes que se pueden alcanzar desde la parte a comprobar. Si cambiamos una parte hay que verificar todas las partes que la usan y las partes que usan a estas sucesivamente. Esto se conoce como análisis de impacto
Reutilidad. Para identificar un subsistema –un conjunto de partes—que se pueda reutilizar, debemos verificar que ninguna de las partes del mismo use cualquier otra parte que no pertenezca al subsistema. El mismo principio nos indica cómo encontrar un subsistema mínimo para una implementación inicial
Orden de construcción. Ayuda a determinar el orden en el que construir las partes. Podríamos asociar dos conjuntos de partes a dos grupos distintos, y hacer que funcionaran en paralelo. Al verificar de que ninguna parte de un conjunto usa a una parte del otro conjunto, nos aseguramos de que ningún grupo sufrirá retrasos por tener que esperar al otro. Podemos de este modo construir un sistema de manera incremental, comenzando por los niveles inferiores del diagrama de casos de uso, por las partes que no hacen uso de ninguna otra parte, y luego ir subiendo, interconectando y testeando cada vez que tengamos un subsistema consistente.
Problema
Hay que encontrar todas las partes que puedan alcanzarse o bien alcanzar una parte.
En un sistema grande son muchas partes y cada vez crece más
La relación básica que sustenta a los usos es transitiva: Si A se ve afectada por B, y B se ve afectada por C, entonces A se ve afectada por C.
Sería mucho mejor si argumentar sobre una parte, por ejemplo, exigiese examinar sólo las partes a las que ésta se refiere.
Dependencias y especificaciones
La solución: que la dependencia de las partes sea sólo un paso del diagrama.
Analizar una parte A será analizar las partes de las que A depende.
Todas las partes de las que A depende deben estar terminadas, su descripción caracterice totalmente su comportamiento
Esas partes no pueden depender de otras partes más que de A
Estos puntos se conocen con el nombre de especificación
Una especificación no se puede ejecutar,
para cada parte de la especificación necesitaremos al menos una parte de la implementación que se comporte según la especificación.
El diagrama de dependencias presenta dos tipos de arcos.
Una parte de la implementación puede depender de una parte de la especificación, y puede que satisfaga o cumpla con una parte de la especificación.
A y B ahora pasa a ser dos relaciones separadas: Al introducir una parte de la especificación S, podemos decir que A depende (depends) de S y B satisface (meets) a S
Se han utilizado dos líneas dobles para distinguir las partes de la especificación de las partes de la implementación.
(...)
Especificaciones de procedimientos
Estructura de la especificación
La especificación de un método consta de:
Una precondición (requires)
Una poscondición (effects)
Una condición estructural (modifies)
Especificaciones declarativas
Indican las propiedades del resultado final en relación con el estado inicial del método.
No indican los pasos de dentro del método
Son preferibles a las especificaciones operativas pues son más cortas
Precondición
Una obligación que se debe satisfacer al llamar al método.
Es una condición sobre el estado en que se invoca al método.
Si no se cumple: no terminar la ejecución, devolver un valor arbitrario, lanzar una excepción, hacer modificaciones arbitrarias, etc.
Si se omite la precondición se presupone el valor true es decir cualquier estado del sistema al llamar al método sastisface la precondición. No hay que comprobar nada al inicio, se llama total en contra los métodos con precondición que reciben el nombre parcial pues sólo funcionan en algunos casos.
La precondición no implica una comprobación, sino que requiere una propiedad precisa, porque la comprobación resultaría complicada o costosa (aumenta la complejidad).
Las precondiciones -> métodos que no siempre funcionan -> métodos que no gustan a los desarrolladores.
Las precondiciones se pueden comprobar mediante Asserts para que no afecten a la ejecución real y puedan detectarse en la depuración.
Poscondición
Es una obligación del implementador del método.
Si se cumple la precondición en el momento de la llamada al método, tiene que cumplirse la poscondición.
No se puede omitir la poscondición, el método siempre debe hacer alguna cosa.
Condición estructural
Está relacionada con la poscondición pues la amplía de forma más detallada.
Indica todos los objetos que pueden o no cambiar en la ejecución del método
Si se omite la condición estructural, el valor por defecto es modifies nothing indicando que el método no realiza cambios en ningún objeto.
Especificaciones operativas
Indican todos los pasos uno a uno, por ejemplo, pseudocódigo.
_________________________________________________________________________________________________________
WikiOtros [camelCaseWordsEnabled: false]