1
Ingenierı́a del software
Contenido
1. Ingenierı́a del software 1
1.1. Desarrollo actual de proyectos de software . . . . . . . . . . . . . . . . . . . . . . . 2
1.2. Ciclo de vida del software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.1. Modelos orientados hacia la especificación . . . . . . . . . . . . . . . . . . . 4
1.2.2. Modelos de desarrollo evolutivos . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.3. Modelos iterativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.4. Transformaciones formales . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.5. Desarrollo aséptico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.6. Aplicabilidad de cada modelo . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3. Fundamentos del diseño del software . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.1. Diseño por encapsulado y ocultamiento . . . . . . . . . . . . . . . . . . . . 11
1.3.2. Modularidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3.3. TADs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.4. POO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.5. Abstracción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.6. Ocultación de información . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.7. Independencia funcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.8. Cohesión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.9. Acoplamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4. Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
análisis
especificación
diseño
implementación
mantenimiento
de grupos de trabajo para resolver la compleja e inmensa maquinaria de relojerı́a que es una
gran aplicación de software. Las correctas costumbres en programación. La poca duración de
las aplicaciones de software por su insuficiente flexibilidad para adaptarse a las continuamente
nuevas necesidades de los usuarios y el alto costo de su desarrollo nos deben hacer ver la gran
importancia de seguir buenas técnicas de gestión de software.
por otro lado, ¿qué es el diseño?, caracterı́sticas (top-down, modularidad, diseño orientado
a objetos);
las técnicas de implementación concretas (portabilidad, control de excepciones, reutilizabi-
lidad), verificación (empı́rica y formal)
y, finalmente, en el Ciclo de Vida primitivo (ver Fig. 1), podemos ver la serie temporal inicial de
que sitúa esquemas generales de trabajo en cuanto a documentación, estilo, etcétera, dentro del
entorno de trabajo a seguir.
Una de las mejores referencias históricas al ciclo de vida del software es la de Yourdon (en
[You88], o [YC79]); los tiempos empleados en cada etapa y la misión de las herramientas CASE
se pueden ver en el clásico [Fis88].
Aunque no la única, una de las propiedades más importantes que garantizan una efi-
ciente construcción de software es la reusabilidad.
En términos generales se puede llegar a decir que la pérdidad de reusa-
bilidad en informática es su pérdida de valor.
Dentro de un ciclo de vida se enumeran y definen las caracterı́sticas que hacen a un software
de calidad (Fig. 2).
La modularidad inicialmente y sobre ella, a un nivel de abstracción más alto, la programa-
ción orientada a objetos, son hoy dı́a imprescindibles para cualquier proyecto de ingenierı́a. Para
entender esto, tenemos que entender cómo la programación es un proceso de ingenierı́a en el que
cada uno de nosotros es parte dentro de un grupo de trabajo1 .
En adelante se hará hincapié en la realización de programas mediante módulos especificados
formalmente en su totalidad, con interfaces de uso perfectamente documentadas. Las caracterı́sticas
que formalmente debe ofrecer este interfaz lo han de convertir en un conjunto coherente, completo
1 Con respecto a la modularidad en concreto, es recomendable la lectura complementaria del artı́culo de Barbara
Liskov [Lis81] en la que se desarrolla un ejemplo completo de un programa formateador de textos en lenguaje CLU.
1.1 Desarrollo actual de proyectos de software 3
Corrección
Fiabilidad
Conveniencia al usuario
Adecuado
Aprendible
Robusto
Mantenibilidad
Legibilidad
Expandibilidad
Comprobabilidad
Eficiencia
Portabilidad
y no redundante de procedimientos, tipos, etcétera, que cubran la finalidad del módulo en el nivel
de abstracción planteado2 .
Como ejemplo sencillo de esta jerarquización de niveles que aparecen tanto en relación con
las estructuras de datos como con las de control podemos ver la diagramación de flujos de datos
que, al contrario que los diagramas de estructuras, están bastante unificados en su presentación
y simbologı́a. En un diagrama de flujo de datos en distintos niveles, desde el nivel “cero” que se
refiere a las entidades que intervienen, a niveles inferiores de detalle, de miniespecificaciones.
Se clasificarán los componentes de software desde el punto de vista de su finalidad y de
las propiedades de su implementación. A lo largo del curso se va a trabajar frecuentemente con
diferentes implementaciones de TADs. Estas implementaciones necesitarán ser caracterizadas por
sus propiedades respecto a diversos conceptos: acotación, concurrencia, recolección de memoria no
usado, etc.
Para poder reutilizar los módulos y objetos se usan distintos mecanismos y recursos que
permiten la su abstracción: genericidad, instanciación, tipos de parámetros genéricos, librerı́as y
sublibrerı́as; lo que repercute en la composición de grupos de trabajo, etc.
En este sentido los lenguajes de programación han ido evolucionando y adoptando estos
criterios en mayor o menor grado dependiendo de su finalidad: C, Pascal, Modula2, Ada, C++,
etc., fueron precursores de la programación orientada a objetos, como la de SmallTalk, C++, Eiffel
etc., hoy presente en todos los lenguajes de desarrollo3 .
2 Es muy importante definir desde un principio lo que se entiende por “nivel de abstracción”. Esto puede ser
relacionado con el ciclo de vida del software, desde un nivel de especificaciones a niveles de detalle en las mi-
niespecificaciones. También puede ser asociado en el desarrollo “top-down”, al nivel de detalle de las operaciones,
vistas en primera aproximación, como sentencias generales que en sucesivas aproximaciones se van a ir refiriendo a
instrucciones a “bajo nivel”
3 Una lectura complementaria que introduce al concepto de programación orientada a objetos es [Boo86], donde,
con la sintaxis de paquetes de Ada, se presentan los conceptos básicos de programación orientada a objetos.
1.2 Ciclo de vida del software 4
Mantenimiento
Prototipado evolutivo (Fig. 6). Los prototipos sucesivos son modificados hasta constituir el
propio software que finalmente usará el cliente.
Propuesta Evalución
nuevos requ. de prototipo
El modelo incremental sugerido por Mills, en 1980, divide el proceso en conjuntos de procesos
menores, que se identifican y resuelven por separado.
El el modelo incremental el cliente identifica y esquematiza los servicios esperados por el
sistema priorizándolos. Esta priorización es tenida en cuenta a la hora del desarrollo. De la es-
quematización y división surgen partes a ser resueltas por distintas partes del sistema. Una vez
que uno de los incrementos se ha completado y puesto en funcionamiento, el cliente puede usarlo
teniéndose ası́ en cuenta sus sugerencias tanto para mejorar esa parte como para reestructurar
y mejorar las demás. No es imprescindible utilizar el mismo proceso con cada incremento en el
desarrollo.
1.2 Ciclo de vida del software 7
Aunque las ventajas son evidentes, los inconvenientes también aparecen, como:
1. Identificación de los incrementos que deben ser relativamente pequeños (de no más de unas
20.000 lı́neas de código) y cubrir alguna funcionalidad, siendo difı́cil, en muchos casos asociar
requisitos del cliente con funcionalidades del sistema. Los requisitos, normalmente no son
independientes y la consecución de uno implica el desarrollo de varios.
2. Infraestructura necesaria Muchos sistemas exigen de la implantación de una infraestructura
común a varias partes del sistema. Esto dificulta aún más la independencia de las partes del
sistema.
3. Gestión de los contratos Ya que partes del sistema no se saben cuándo van a empezar, es
difı́cil llevar un sistema de contrataciones y organizar el trabajo del personal involucrado,
que usualmente debe fijarse con horarios y fechas desde el principio.
Diseño de la Desarrollo de
arquitectura servicios básicos
del sistema
NO
SÍ
Entrega final
Este último aspecto se elimina en la variante de entrega incremental que sigue las primeras
etapas, pero no pospone las especificaciones de ninguna otra de manera que se puedan prever los
contratos y fechas de trabajo.
E
ide val
nt uac
ific ió
ac n d
ió e
Análisis rie n, r alte
es
ci e
sg es rn
ric d
on
de riesgos os olu at
st n
re ció
ció iva
y ina
n s,
de
os m
Análisis
tiv er
je et
de riesgos
ob D
Análisis Protot.
de riesgos operativo
Protot.
Prot. 3
Análisis
de riesg 2
Prot.
REVISIÓN 1
Sim
plan de ula cion
requisitos y es, m
Concepto de odelo
de ciclo de vida s, co
operaciones mpa
rativ
as
Requ. de
SW
plan de Validación Diseño Diseño
desarrollo requis. producto detallado
pl sig
código
an u
la
ifi ien
integración y test
ca te
diseño unidades
ci f
plan de pruebas n ón
ón as
integración i f
test er pr
aceptación ,v e
servicio o llo el d
rr iv
sa e n
Deient
u
sig
Un tı́pico riesgo es la inadecuación de la interfaz de usuario, por ejemplo, al tipo de uso que se
quiere del sistema, por ejemplo en un sistema que pretende ser de tipo “walk up and use”, en el que
se requerirá una gran facilidad de manejo para todos. Aquı́ un fallo en la interfaz serı́a un desastre
para el sistema completo. Esto se resuelve en la etapa que corresponda mediante la construcción de
bocetos y prototipos parciales que habrán de testearse ampliamente antes de abordar su desarrollo.
Este modelo abarca a otros. Donde no hay un gran riesgo en la recogida de requisitos se
convierte en un sencillo modelo en cascada, mientras que en sistemas de más compleja defini-
ción de requisitos, como en los sistemas altamente interactivos, el sistema puede ser considerado
como un sistema evolutivo con las actividades de prototipado dominando y un tercer cuadrante
relativamente pequeño (ver Figura 8).
Las dos grandes dificultades de este modelo son
1. La dificultad del análisis de riesgos, que requiere personal con experiencia y altamente espe-
cializado.
2. Los problemas de contratación, ya que este modelo trata de evitar decisiones prematuras,
que son, por otro lado esenciales a la hora de prever fechas de contratación.
1.2 Ciclo de vida del software 9
Este modelo requiere de un alto grado de cercanı́a o confianza entre el cliente y los desarrolladores.
Requisitos
del sistema
Pruebas Pruebas
estadísticas al sistema
al diseño integrado
el desarrollo de las funciones del sistemas de la interfaz que los usará. Son sin embargo enfoques
adecuados a problemas pequeños y bien definidos. Son además principios muy importantes en
muchos otros enfoques de diseño.
Los DFDs permiten el diseño atendiendo a los datos, a las entradas y salidas, caracterización
de los datos que deben llegar y salir y de los procesos que descritos sobre todo en función de la
manera de transformar esos datos.
Esta representación del sistema permite además la exploración de las funciones en detalle.
Mediante la jerarquización de los diagramas, hasta llegar a las miniespecificaciones.
Los DFDs son muy populares y aún hoy se usan dado su sencillez de interpretación.
Entre los defectos de los DFDs están su incapacidad para la representación de iteraciones
entre tareas. Son una notación semiformal e incompleta y deben ser complementados con otras
técnicas.
Los DER sirven para detallar las estructuras de datos y su interrelación complementando
ası́ la descripción más grosera de los DFDs. Los DER utilizan la interrelación para modelar las
asociaciones de información estáticas entre entidades. Éstas tendrán cardinalidades (uno-a-uno,
uno-a-muchos o muchos-a-muchos) y atributos, incluyéndose hoy en ellos relaciones de herencia.
Las MEF capturan los aspectos de control del sistema. Para ello establecen estados que re-
presentan puntos funcionales del diseño, representando con arcos etiquetados los diferentes valores
(en forma de frases) que causarı́an a aquél estado un cambio o transición a otro estado.
1.3.2. Modularidad
El concepto de módulo fue propuesto inicialmente por Parnas a principio de los 70 y fue imple-
mentado en lenguajes como Modula-2 y Ada. Su origen estuvo en el examen de programas reales
que mostraban soluciones de enfoque comunes independientemente del dominio de la aplicación.
Particularmente se veı́a que una estructura de datos dada mostraba siempre una compañı́a de fun-
ciones que permitı́an su acceso y posibilidades. En lenguajes como C esto se recogı́a organizando en
ficheros separados la estructura del programa. Los módulos formalizaron este proceso reconocien-
do la particionabilidad de los programas en unidades discretas con una interacción explı́citamente
representada y, por tanto, perfectamente definida. Individualmente cada unidad de programa en-
capsulaba la funcionalidad deseada para una tarea y ofrecı́a una interfaz para su cliente (otro
módulo) mientras ocultaba su implementación.
Los módulos ofrecı́an pues la posibilidad de encapsular la funcionalidad y permitir futuros
cambios.
1.3 Fundamentos del diseño del software 12
Desde muchos puntos de vista la modularidad reflejaba el enfoque top-down del refinamiento
por pasos sucesivos.
Los módulos encajaban bien con las descripciones de los DFDs y DER, siendo una técnica
orientada a los diseñadores de software más que a los usuarios finales de los programas.
1.3.3. TADs
Los TADs fueron propuestos inicialmente por Liskov para el lenguaje de programación CLU
a finales de los 70. Un TAD está caracterizado por una información almacenable y una serie de
procedimientos de acceso, modificación y recorrido, que reflejan todo su comportamiento externo.
La implementación privada de los TADs queda oculta al cliente del mismo, que es el propio
diseñador en otra parte del diseño.
En realidad los TADs no son una idea nueva como concepto ya que los tipos definidos por los
lenguajes de programación tienen más que ningún otro, comportamiento de TADs. Por ejemplo,
el tipo entero y las operaciones que lo permiten manejar (+, -, *, div y mod) nos abstraen del
mecanismo interno de su implementación.
Los TADs dan lugar a una programación más orientada a los datos y su uso. Para ello debemos:
Identificar las unidades de información principales.
Describir el propósito de cada unidad.
Definir las técnicas de manipulación para cada unidad.
Encapsular y ocultar los aspectos no definidos.
Claramente las ventajas del uso de los TADs son las mismas que la del uso de los módulos,
sin embargo, que estas técnicas son particulares para cada parte del proceso, los errores se pueden
arrastrar a todos ellos. Además la carencia de patrones y la falta de la herencia de caracterı́sticas
hacen que la construcción de TADs en un proyecto pueda dar lugar un alto grado de redundancia
de código. TADs que pueden ser semejantes pero sólo difieran en alguna pequeña caracterı́sti-
cas tendrán igualmente que ser implementados por separado con la repetición del código. Estas
carencias hacen de los TADs menos reutilizables.
1.3.4. POO
La transición hacia el diseño OO a partir de las especificaciones no es una actividad trivial.
No existen técnicas globales que permitan la transición de DER directamente hacia una POO.
Dado que los enfoques DFD y DER son en parte contrarios, su concreción en un lenguaje OO
es contradictorio. Es por esto que la mayorı́a de los lenguajes OO encierran su propio enfoque de
lo que es el proceso de diseño utilizando una unidad de encapsulamiento/abstracción llamada tipo
de objeto o clase, con un fuerte paralelismo con el concepto de TAD. La diferencia fundamental
con el TAD está en el concepto de herencia. La herencia permite la compartición controlada
de propiedades entre objetos/clases permitiendo ası́ el recoger tanto datos componentes como
operaciones admisibles desde el supertipo o superclase al subtipo o subclase.
La POO es adecuada porque:
Refuerza la modularidad.
Incrementa la productividad.
Controla la consistencia de la información.
Favorece la reusabilidad del software.
Facilita la evolución del software.
Aunque no hay un total acuerdo en cuanto a la terminologı́a respeto al diseño OO, podemos
describir los siguientes conceptos comunes:
1.3 Fundamentos del diseño del software 13
Tipo objeto/clase: sirve para modelar las caracterı́sticas (en forma de información recogible)
y el comportamiento (métodos utilizables) para una aplicación.
Información: tipos privados de un TO/clase. Representa su estado interno caracterizando la
instancia.
Método: procedimiento requerido para una acción particular contra los datos privados del
TO/clase.
Herencia: compartición controlada de la información/métodos entre TO/clases entendién-
dose esta compartición como una herencia de más TO/clases más generales a otros más
particulares, subclases, que repiten todos o parte de la composición del ancestro, substitu-
yendo, probablemente algunos de sus métodos/datos, y añadiendo o eliminando otros. Pero
siempre tomando como punto de partida el conjunto de propiedades de la superclase.
Instancia: Concreción en un TO/clase de una información y métodos.
Mensaje: Acción, llamada a método, que puede ser lanzada por la propia instancia sobre
sı́ misma o otras instancias de otros.
1.3.5. Abstracción
La abstracción es una técnica de desarrollo muy potente que permite ignorar los detalles y
utilizar tan sólo los elementos, simplificadamente, menos farragosos, de un nivel más abstracto en
el que sólo nos interesan caracterı́sticas dadas del módulo o componente de software.
La abstracción en el desarrollo del software se consigue mediente la independización de los
detalles en bloques no visibles.
1.3.8. Cohesión
La cohesión es la cualidad más importante para hacer que los módulos sean independientes
ya que representa el hilo conductor que une internamente las piezas de un módulo. Si este hilo es
único y sencillo todas piezas del módulo encontrarán los elementos necesarios para su funciona-
miento dentro del propio módulo. Si existen varios la multiplicidad implicará mayor dependencia
de módulos externos ası́ como una más complicada idea de su funcionamiento.
1.3.9. Acoplamiento
El acoplamiento entre módulos surge de la falta de coherencia interna de los mismos o su
complicada definición. En general, sin embargo, es imposible de evitar totalmente siendo una ca-
racterı́stica natural un acoplamiento controlado entre los módulos. Esta dependencia controlada se
1.4 Referencias 14
1.4. Referencias
Textos fundamentales, traducidos y asequibles son los de [Pre93] y [Som96]
Referencias
[Boo86] Grady Booch. Object-oriented development. IEEE Transactions on Software Enginee-
ring, 12(2):211–221, February 1986.
[Fis88] Alan S. Fisher. Case. Using Software Development Tools. John Wiley & Sons, 1988.
[Lis81] Barbara Liskov. Modular program construction using abstractions. Technical report,
MIT. Dept. of Elect. Eng. and Comp. Sci., Cambridge, Mass. 02139/USA, March 1981.
Interesante y sencillo de leer, este artı́culo basa un ejemplo desarrollado en CLU en la
abstracción y stepwise refinement de Dijstra y Wirth. El ejemplo es un detenido desarrollo
de un formateador de texto.
[Pre93] Roger S. Pressman. Ingenierı́a del Software. Un enfoque práctico. McGraw-Hill, 1993.
Ya va por la cuarta edición. Referencia obligada para todos los programadores. Ofrece
una visión global y muy completa de todos los problemas y modelos de la programación
de sistemas. Puede resultar un poco superficial en algunos terrenos debido naturalmente
al espacio limitado del texto. Extensa bibliografı́a.
[Som96] Ian Sommerville. Software Engineering. Addison-Wesley, 5th edition, 1996. Clásico
introductorio sobre la problemática general de la Ingenierı́a del Software. Más breve y
con menos bibliografı́a.
[YC79] Edward Yourdon and Larry L. Constantine. Structured Design. Fundamentals of a Dis-
cipline of Computer Program and Systems Design. Yourdon Press, 1979.
[You88] Edward Yourdon. Managing the System Life Cycle. Prentice-Hall, second edition, 1988.
Juan Falgueras
Dpto. Lenguajes y Ciencias de la Computación
Universidad de Málaga
Despacho 3.2.32