Universidad de Costa Rica Facultad de Ciencias Escuela de Matemática Departamento de Ciencias de la Computación +------------------------------------+ | Diseño y Programación Estructurada | +------------------------------------+ Autor: Adolfo Di Mare +----------------------------+ |"Si no se sabe adónde se va | | se llega otro lado" | | (Fórmulas de Péter) | +----------------------------+ (Capítulo 3 del libro Fundamento de Algoritmos y Lenguajes, Noviembre 1978, Javier Gaínza, editor) 3.1 Introducción ================ En este capítulo expondremos dos técnicas muy usadas en la actualidad para lograr que grandes sistemas de computación no "se desplomen" por errores en el diseño o la programación. Estas dos técnicas son el diseño de arriba hacia abajo (usada para análisis y diseño del sistema) y la programación estructurada. 3.2 Generalidades ================= Para resolver un problema específico con ayuda del computador se siguen los siguientes pasos: 1- Preparación de la descripción precisa del problema. 2- Selección del método a usar para resolver el problema y determinación de entradas y salidas. 3- Expresión del método como un algoritmo (deben tomarse en cuenta los datos y la relación entre ellos). 4- Traducción del algoritmo a un lenguaje de computación (programa de computadora). 5- Verificación del buen funcionamiento del programa (Pruebas del programa). 6- Corrida y obtención de resultados (Programa en producción). Las primeras dos etapas son conocidas como "Análisis y Diseño" y comúnmente se conoce como "programación" a la ejecución de los pasos 3, 4 y 5. Podemos definir la programación como un método o proceso para crear programas de computadora (secuencia de instrucciones que pueden ser ejecutadas por un computador). Con frecuencia las etapas 1 y 2 son asignadas a una persona (el analista) y las restantes a otra (el programador). Esta división es, muchas veces, poco práctica (principalmente cuando el usuario no sabe exactamente qué es lo que desea). En estas líneas está descrita una técnica que permite ahorrar mucho esfuerzo (dinero) en el desarrollo, mantenimiento, uso y extensión de programas. Esta técnica es el diseño de arriba hacia abajo (Top-down Design o TDD) y la programación estructurada (PE). Lo mente humana es un instrumento de enorme poder. Sin embargo, no es capaz de abarcar grandes cantidades do información en un mismo momento. Para visualizar esto imaginamos un buque petrolero: es fácil distinguir su timón, las 4 hélices, el enorme casco y la intrincada cantidad de tuberías en cubierta. Pero tratemos ahora de imaginar 1000 petroleros; nuestra mente, simplemente, no puede abarcarlos. Por la razón anteriormente expuesta, no hay persona capaz de mantener una idea "fresca y congruente" de un programa que tenga 20 o mas páginas de instrucciones. Otro ejemplo: de todos es conocido que si un teorema tiene demasiadas hipótesis es, entonces, muy difícil de aplicar. Es claro que el "tamaño" es una variable que incide directamente en nuestra capacidad de comprensión. Por esta razón nosotros debemos organizar nuestras ideas (y programas) de manera tal que nos sean comprensibles fácilmente. Para lograr esto dividimos nuestro problema en varios subproblemas (y estos los subdividimos a su vez) hasta llegar a tener una multitud de subproblemas relacionados que comprenderemos fácilmente. Este método se llama "Análisis de Arriba hacia Abajo" y es una técnica muy usada en el diseño de grandes sistemas (Top-down Design, TDD, o diseño de arriba hacia abajo). Esto se ve, esquemáticamente como sigue: +-------+ | | +-------+ | +-----------------------+ | | | +-------+ +-------+ +-------+ | | | | | | +-------+ +-------+ +-------+ | | +-----------+ +-----------+ | | | | +-------+ +-------+ +-------+ +-------+ | | | | | | | | +-------+ +-------+ +-------+ +-------+ Hablemos ahora de la claridad: para solucionar un problema es necesario comprenderlo. Para la comprensión de un problema es necesaria, la claridad en su análisis. La claridad nos hace preferir la escritura a máquina a la escritura a mano ( ¡Por la claridad y nitidez tanto ayudan las secretarias! ). Por eso al diseñar un sistema deberá siempre tomarse en cuenta la nitidez del diseño. 3.3 Análisis y diseño del Sistema: ================================= 3.3.1 Diseño de arriba hacia abajo ---------------------------------- Dado un problema de computación el TDD consiste en desglosar el problema en varios subproblemas y estos a su vez, desglosarlos hasta obtener un conjunto de módulos inter-relacionados cada uno de los cuales es fácilmente comprensible y, por ende, fácilmente soluble. En resumen, se busca lograr diseñar un sistema (o programa) de una manera precisa y ordenada. El TDD significa, esencialmente, proceder por refinamiento. En cada nivel (de desglose) la función a ser ejecutada es definida y expresada en términos de unidades funcionales de más bajo nivel, continuando el proceso hasta que se alcanza un nivel en el que es posible escribir la solución del problema en un lenguaje de computación. Se ha desarrollado software para simular las funciones de bajo nivel cuando se está en un nivel superior. Se introducen entonces, las cepas (STUBS) que son módulos que eventualmente serán desarrollados. De esta manera es posible comenzar a codificar en niveles superiores e inferiores simultáneamente y, más aún, se define, en cada nivel, un conjunto de sistemas que funcionan. Según Dijsktra cada nivel jerárquico de módulos de software genera un recurso abstracto que descansa sobre niveles jerárquicos inferiores y que está disponible para niveles superiores en la jerarquía. Así, en cada nivel se manejan recursos soportados en niveles inferiores. Para ver esto con más claridad imaginemos que queremos desarrollar un paquete para la manipulación de archivos. Estos archivos se pueden ver como una colección de vectores que a su vez son una colección de palabras. Se pueden hacer programas para manipular archivos, o sea, extraer algún vector en particular. El siguiente nivel de programas opera sólo en vectores extrayendo palabras de los vectores que fueron leídos con los programas de manipulación de archivos. Entonces el esquema de jerarquía es: +----------+ | Archivos | +----------+ / +-----------+/ | programas | +-----------+\ \ +----------+ | Vectores | +----------+ / +-----------+/ | programas | +-----------+\ \ +----------+ | Palabras | +----------+ Dijstra advierte que debe tenerse un cuidado especial de asegurarse de que cada nivel esté completo, esto es, verificar que las operaciones en un nivel no sean soportadas por el recurso abstracto proveído por los niveles inferiores; además es necesario que las relaciones entre los niveles (y módulos) estén bien definidas (parece no haber una teoría o modelo matemático que pueda ser usado do para la verificación de lo anterior). 3.3.2 Ejemplo: Diseño de un Ensamblador --------------------------------------- Para la serie de libros de titulo "The art of computer programming" Donald Knuth diseñó una máquina ficticia (la máquina MIX) y el correspondiente lenguaje ensamblador (el lenguaje MIXAL). Veamos una rutina escrita en MIXAL: +--------------------------+ | X EQU 1000 | | ORIG 3000 | | MAX STJ EXIT | | INIT ENT 3 0,1 | | JMP CHANGEM | | LOOP CMPA X,3 | | JGE +3 | | CHANGEM ENT 2 0,3 | | LDA X,3 | | DEC 3 1 | | J3P LOOP | | EXIT JUMP 0 | +--------------------------+ Si queremos hacer un programa ensamblador debemos, primero, estudiar el lenguaje MIXAL. Examinando el programa anterior observamos la necesidad de contar con un directorio de instrucciones mnemónicas (para así reconocer cada una de ellas) y la necesidad de contar con un directorio de etiquetas (para saber, en cada referencia, el significado de esta referencia). La estructura de estos directorios no será discutida (para no prolongar mucho la exposición). Supondremos que existen estos directorios y las rutinas necesarias para accesarlos. Una vez definidos estos datos básicos, podemos comenzar a definir los diferentes procesos que formarán el ensamblador. Generalmente un programa escrito en lenguaje ensamblador entra al computador por tarjetas en registros de 80 columnas. Como nosotros no sabemos cuál será el tamaño del programa nos es lógico el admitir que sólo podremos procesar un registro a la vez. Necesitaremos un programa LECTOR: su función será leer cada registro de 80 columnas y procesarlo (al hablar de "procesarlo" hablamos de un recurso abstracto). Aclaremos ahora el término "procesar". Si ya hemos leído una tarjeta deberemos examinarla: toda tarjeta en lenguaje ensamblador tiene, como máximo, 4 componentes: 1- Etiqueta (campo de localización). 2- Operación (aquí se escribe siempre un mnemónico). 3- Operandos (a quiénes se les aplica la operación). 4- Comentarios aclaratorios a la lógica del programa. Si suponemos que nuestro programa ensamblador no exigirá al usuario un formato fijo para los campos anteriormente mencionados deberemos construir una rutina (llamémosla PACK) que deje, cada vez que se lee un nuevo registro, la misma información del registro leído pero dejando cada uno de los campos en un lugar determinado. Hasta el momento hemos definido 2 rutinas: +--------+ | LECTOR | +--------+ | +------------------------------+ | +------+ | PACK | +------+ Analicemos ahora el campo de los operandos. En este campo pueden aparecer referencias futuras; como procesamos uno a uno los registros del programa, no podemos conocer el lugar adonde esta situada una referencia futura. De aquí surge la necesidad de hacer 2 pasadas sobre los registros iniciales: en la primera pasada deberemos construir el directorio de etiquetas y en la segunda deberemos procesar cada instrucción (con ayuda del directorio). Vemos, entonces, la necesidad de 2 nuevos módulos (uno para cada pasada). Esquemáticamente lo podemos ver así: +--------+ | LECTOR | +--------+ | +---------------+--------------+--------------------------+ | | | +------+ +-------+ +-------+ | PACK | | PASO1 | | PASO2 | +------+ +-------+ +-------+ Analicemos ahora el módulo PASO1: su función primordial será crear el directorio de etiquetas. Para esto definimos la rutina INCLUYE la cual cada vez que aparezca una variable en el campo de localización de un instrucción incluirá esa variable en el directorio de etiquetas. Analizando con detenimiento el programa ejemplo (al principio del ejemplo) encontramos las seudo-instrucciones ORIG y EQU. Estas seudo-instrucciones deben procesarse de manera distinta a como se procesan las instrucciones usuales de MIXAL por lo que creamos un módulo para procesar cada una de ellas: el módulo EQU y el módulo ORIG. Como debemos verificar en la primera pasada la aparición de los seudos EQU y ORIG es sensato pensar en verificar la validez de todas las demás instrucciones del lenguaje ensamblador: creamos de esta manera el nuevo módulo CHEKEAR. Nuestro diagrama, hasta el momento, se ve como sigue: +--------+ | LECTOR | +--------+ | +---------------+--------------+--------------------------+ | | | +------+ +-------+ +-------+ | PACK | | PASO1 | | PASO2 | +------+ +-------+ +-------+ | +---------+---+---+----------+ | | | | +---------+ +-----+ +------+ +---------+ | INCLUYE | | EQU | | ORIG | | CHEKEAR | +---------+ +-----+ +------+ +---------+ El nivel de diseño puede continuar hasta llegar a definir completamente la función de cada módulo y su relación con los demás. Es importante nota que en la definición de procesos se puede hacer la definición de los datos que interrelacionen los procesos. No se ha hecho aquí para dar más claridad a la exposición. El ejemplo muestra la técnica de diseño de arriba hacia abajo. Nótese que esta técnica permite, conforme se diseña, comprender cada vez mejor el problema. Fijemos nuestra atención en el segundo módulo el cual deberá procesar el campo de los operandos (el primero no lo puede hacer pues, en el primer paso, no está totalmente construido el directorio de etiquetas). Como en este campo existen variables simbólicas y expresiones deberemos crear 3 nuevos módulos: uno para desglosar cada expresión (DESGLOSE), otro para sustituir cada variable por su valor correspondiente (CONVIERTA) y un tercero para evaluar expresiones (OPERADOR). Nuestro esquema general se ve de esta manera: +--------+ | LECTOR | +--------+ | +---------------+--------------+--------------------------+ | | | +------+ +-------+ +-------+ | PACK | | PASO1 | | PASO2 | +------+ +-------+ +-------+ | | +---------+---+---+----------+ +-----------+------------+ | | | | | | | +---------+ +-----+ +------+ +---------+ +----------+ +---------+ +----------+ | INCLUYE | | EQU | | ORIG | | CHEKEAR | | DESGLOSE | |CONVIERTA| | OPERADOR | +---------+ +-----+ +------+ +---------+ +----------+ +---------+ +----------+ Nótese que la rutina CONVIERTA deberá usar una rutina para accesar el índice de símbolos. Además deberemos definir exactamente que es "desglosar" así como todas las operaciones válidas para poder definir, entonces, las rutinas DESGLOSE Y OPERA. Una vez que todo este definido podemos comenzar a programar esta rutinas. Otra de las características importantes del TDD es su gran adaptabilidad cuando sobrevienen cambios. Muchas veces el (futuro) usuario de un sistema en desarrollo necesita cosas distintas de las que se le estaban proveyendo. Como el TDD permite esquematizar el sistema en desarrollo es entonces posible adecuarlo al cambio sin necesidad de una revisión total del diseño. 3.3.3 Otras consideraciones --------------------------- Con frecuencia es importante desarrollar e implementar un sistema muy rápidamente. Usualmente, para logro esto, se diseña el sistema de arriba hacia abajo y luego se implementa inmediatamente en APL (lenguaje interpretativo de alto poder). De esta manera obtenemos un modelo del sistema que funciona (aunque puede ser muy lento). Una variante de la técnica anterior es programar en APL y, simultáneamente, programar en el lenguaje apropiado (COBOL, PL/1, FORTRAN, etc.). De esta manera construimos un modelo que funciona y remplazamos, paulatinamente, los módulos APL por módulos más rápidos (COBOL, u otros). El uso de esta técnica ha reportado incrementos hasta de un 50% en el desarrollo de diferentes sistemas de computación. A veces necesitamos que los sistemas sean muy confiables. Para lograr esto simplemente diseñamos el sistema de arriba hacia abajo, lo programamos y luego lo probamos de abajo hacia arriba (Top down, bottom up). Con esto obtenemos, en cada nivel jerárquico del sistema en desarrollo la certeza de un buen funcionamiento. Es claro que disponemos de 2 formas de probar los distintos niveles do un sistema: 1- Con cepas para simular niveles inferiores. 2- Probar de abajo hacia arriba hasta llegar al nivel deseado. 3.3.4 Consideraciones Finales ----------------------------- Básicamente, el diseño de arriba hacia abajo es: l. Diseño y análisis claro y en fases. 2. Implementación por fases. 3. Uso de módulos funcionalmente independientes. 4. Aislamiento de secciones volátiles o críticas. 5. Proceder por refinamiento. Entonces, una técnica eficiente de diseño e implementación de sistemas de computación es: l. Diseñar el sistema de arriba hacia abajo. 2. La implementación del sistema debe hacerse, también, de arriba hacia abajo. Las cepas deben usarse lo antes posible. 3. Cada módulo programado debe ser lo más corto posible, preferiblemente no mayor de 1 página, para así facilitar la división del problema en pequeños módulos. 4. La dirección del proyecto debe estar en manos do personas competentes; ellos deben determinar cada módulo y las interrelaciones entre ellos. 3.4 La programación del sistema =============================== 3.4.1 Programación estructurada ------------------------------- Ya hemos hablado suficiente sobre la primera fase en el desarrollo e implantación de un sistema. Veamos ahora una técnica para lograr finalizar las etapas restantes con éxito: la programación estructurada (PE). El término programación estructurada nació cuando Edsger W. Dijsktra publicó sus famosas "Notas en Programación Estructurada" en el año 1972. La idea de Dijsktra es descomponer cada programa en un conjunto de módulos. Cada módulo tendrá una única entrada y una única salida y un módulo podrá tener submódulos. Con la técnica de programación estructurado se reduce la complejidad de un programa aumentando su claridad (con frecuencia la complejidad de un programa dificulta mucho el conocer su función). Cuando un programa es claro es fácil de comprender. Si se desea reducir la complejidad de un programa bastará eliminar: a- Las estructuras confusas. b- Los caminos complicados de control. c- La codificación obsoleta y redundante. d- Los comentarios sin significado, etc. Mejorar la claridad de un programa es añadirle: a- Etiquetas significativas. b- Buenos comentarios. c- Buena estructura de programación, etc. La programación estructurada es una manera de organización y codificación de programas que los hace fácilmente inteligibles y modificables. Mucha de la complejidad de los programas nace del gran número de saltos a diferentes partes del programa (exceso de GO TO 's). En Programación estructurada se busca, principalmente, simplificar los caminos de control. Además, la programación estructurada busca relacionar íntegramente el programa codificado (programa estático) con su función (programa dinámico), esto es, el programa debe reflejar el proceso aplicado a las entradas para producir las salidas. Esta noción do programa estático y dinámico fue introducida por Dijsktra. Muchos de los contratiempos encontrados en el desarrollo de grandes sistemas se deben a la falta de nitidez en la programación. Con PE se evita la programación borrosa. Algunos proyectos han reportado una producción de sólo 3 líneas de código por cada día hombre de trabajo. Usando TDD y PE se ha logrado producir hasta 11 líneas de código por cada hora-hombre. La baja productividad del primer caso se debió a la excesiva corrección de programas, situación que no se dió en el segundo caso pues con PE es posible revisar mas profundamente el programa en el escritorio y es más simple preparar los datos de prueba. Aunque programar estructuradamente es más difícil que no hacerlo, con PE se aumenta considerablemente la productividad del programador. Los logros principales de la programación estructurada son: 1- Construcción de programas sin el uso del "GO TO". 2- Lograr que un programa se lea de arriba hacia abajo (como un libro). 3- Lograr claridad en la codificación. 4- Relacionar el programa "estático" con el "dinámico". 5- Lograr que un módulo sea fácilmente corregido en el escritorio (depuración de escritorio). 6- Lograr que el tamaño de un módulo sea manejable (y por esto podrá ser comprendido fácilmente). Sin embargo, PE es una técnica más de programación; para que sea aplicada debe convencerse a las personas de su excelencia (recordemos que las leyes se derivan de las costumbres de las personas). Discutamos ahora la técnica. Básicamente un programa estructurado está compuesto de bloques (módulos). Estos bloques pueden ser combinados de acuerdo a 6 construcciones básicas que gobiernan la transferencia de control entre los diferentes bloques del programa estructurado. Programación estructurada es la combinación de estos bloques de acuerdo a esas construcciones. Según Dijsktra estas 6 construcciones pueden dividirse en 3 clases: 1- Construcciones de concatenación. 2- Construcciones de selección. 3- Construcciones de repetición. A continucación se discuten las 6 construcciones básicas. 1. Concatenación: Las instrucciones se ejecutan en el orden en que aparecen, donde el control pasa incondicionalmente de un estatuto a otro. Esta construcción es muy simple (trivial) y es necesaria para la secuenciación de bloques. 2. IF 'c' THEN 's'; (Selección) La condición 'c' es probada. Si 'c' es verdadero entonces el bloque 's' es ejecutado. De otra manera, 's' no es ejecutado. El control para a la siguiente instrucción. El estatuto 's' puede ser un bloque o una instrucción simple. Esto es verdadero en cada una de las construcciones sin importar adonde aparezcan. 3. IF 'c' THEN 'a' ELSE 'b' ; (Selección) La condición 'c' es probada. Si 'c' es verdadera se ejecuta el bloque 'a' y el bloque 'b' es ignorado. Si 'c' es falsa, el bloque 'a' es ignorado y se ejecuta el bloque 'b' En ambos casos el control para a la siguiente instrucción. 4. CASE 'i' OF (S1, ... , Sn) ; (Selección) El 'i-ésimo' bloque es seleccionado y ejecutado y todos los demás bloques son ignorados. El control pasa al estatuto siguiente a 'Sn'. 5. WHILE 'c' DO 's' ; (Repetición) La condición 'c' es probada. Si 'c' es verdadera el bloque 's' es ejecutado y se vuelve a hacer otra prueba 'c'. El ciclo continúa hasta que 'c' sea falsa y entonces 's' es ignorado. El control pasa a la siguiente instrucción después de 's'. 6. REPEAT 's' UNTIL 'c' ; (Repetición) 's' es ejecutado y luego la condición 'c' es probada. Si 'c' es falso el control regresa a 's' y se hace otra iteración, si no, el control pasas a la siguiente instrucción. Veamos ahora un programa poco claro y su equivalente estructurado (se usa FORTRAN): +-------------------------------------++-------------------------+ | IF (A .GT. 20) GO TO 2 || IF (A .GT. 20) | | IF (A .GT. 10) GO TO 1 || THEN x = 4.0 | | x = 5 || ELSE IF (A .GT. 10) | | GO TO 3 || THEN x = 6.0 | | 1 X = 6 || ELSE x = 5.0 | | GO TO 3 || ENDIF | | 2 X = 4 || ENDIF | | 3 CONTINUE || | +-------------------------------------++-------------------------+ ¿Será posible reconocer la diferencia? 3.4.2 Programación estructurada en los lenguajes ----------------------------------------------- En este aparte discutiremos la aplicación de la programación estructurada en cada uno de los principales lenguajes de alto nivel: FORTRAN, COBOL, PL/1, ALGOL. 3.4.2.1 FORTRAN --------------- FORTRAN fue uno de los primeros lenguajes en desarrollarse por lo que es un "lenguaje de alto nivel muy bajo". Por esto los compiladores FORTRAN tienden a producir códigos objetos muy eficientes aunque el lenguaje tiene serias desventajas como lenguaje estructurado: 1- FORTRAN no está orientado a ]as estructuras en bloques. Por esta razón el programador debe usar GO TO continuamente. 2- Las subrutinas FORTRAN no son recursivas. El programador FORTRAN no conoce, generalmente, la recursividad. 3- El lenguaje está dirigido al uso de GO TO's de varios tipos. El programador FORTRAN es muy hábil en el uso del GO TO. 4- FORTRAN no tiene formato variable paro escribir las instrucciones. Las etiquetas siempre deben ser numéricas. No obstante lo anterior es posible implementar en FORTRAN la programación estructurada usando para ella, un preprocesador. Un ejemplo tangible es el preprocesador SPARKS (Structured Progrograming A Reasonably Kopmlete Set o Smart Programers Are Required to Know Sparks). Con este preprocesador es posible implementar todas las construcciones básicas de la programación estructurada. SPARKS es un lenguaje que contiene completamente a FORTRAN y tiene, además, algunas instrucciones nuevas (para implementar PE) y algunas palabras reservadas. Veamos algunas de estas construcciones: 1- En concatenacion: Es posible escribir, separado por ';' (punto y coma) varios estatutos SPARKS en un sólo renglón. Ejemplo: A = 3; B = 5; UEC (A,B) = A - B 2- En Selección se tiene: 2.1) IF 'c' THEN 's' ENDIF 2.1) IF 'c' THEN 'S1' ELSE 'S2' ENDIF 2.3) CASE : c1 : 'S1' ... cn : 'Sn' ELSE 'Sn+1' ENDCASE 3- En Repetición tenemos: 3.1) WHILE 'c' DO 's' END DO 3.2) REPEAT 's' UNTIL 'c' END REPEAT Para una referencia más completa, basta ver la referencia (Horowitz y Sahni) en la bibliografía. 3.4.2.2 COBOL ------------- El lenguaje COBOL fue desarrollado después del FORTRAN por lo que es un lenguaje mejor definido y posee una estructura mejor planeada. COBOL tiene algunas características que permiten hacer programas estructurados. Posee por ejemplo: 1- IF 'c' THEN 's' . (El punto del final es importante). 2- IF 'c' THEN 'S1' ELSE 'S2' . 3- GO TO l1, ..., ln DEPNENDING ON 'variable' . (El punto es muy importante en COBOL pues tiene el poder de terminar todos los "IF" que están "pendientes") 4- PERFORM 5- PERFORM UNTIL 6- Posee la estructura clásica de concatenación de instrucciones. Sin embargo, COBOL no posee algún verbo para construir un bloque REPEAT-UNTIL. Además el punto ('.') tiene demasiado poder (es clásico oir de un programador COBOL historias tristes acerca del pequeño gran punto) y las rutinas COBOL no son recursivas. Para ampliar COBOL se han hecho preprocesadores que lo hacen más potente. Un ejemplo es el META COBOL producido por Applied Data Research, Inc. Con META COBOL es posible tener macros, constantes y variablos booleanas, estructura flexible de bloques y algunos verbos nuevos (como el verbo SELECT que sirve para hacer preguntas en cascada). META COBOL es un lenguaje "de más alto nivel que" COBOL pues lo contiene y tiene muchos ventajas adicionales. Aunque existen preprocesadores para COBOL que lo extienden, es posible programar estructuradamente en COBOL (y de hecho muchos personas lo hacen). 3.4.2.3 ALGOL y PL/1 ------------------- Los lenguajes ALGOL y PL/1 han sido estudiados extensamente. Por esto han incorporado en sí todos los requerimientos deseados en un lenguaje para programar estructuradamente. Veamos una comparación de ambos: +-------------------------+-------------------------+ | ALGOL | PL/1 | | | | +----------------------+-------------------------+-------------------------+ | | 'BEGIN' ... 'END' | BEGIN ; .... END ; | | Estructura de bloque | 'PROCEDURE' ... 'END' | DO ... END; | | | | PROCEDURE ... END; | +----------------------+-------------------------+-------------------------+ | | | | | IF ... THEN ... ELSE | Totalmente implementado | Totalmente implementado | | | | | +----------------------+-------------------------+-------------------------+ | | | | | DO ... WHILE | 'FOR'... 'WHILE' | DO ... WHILE | | | | | +----------------------+-------------------------+-------------------------+ | | | | | REPEAT ... UNTIL | 'FOR'... 'UNTIL' | DO ... UNTIL | | | | | +----------------------+-------------------------+-------------------------+ | | | | | RECURIVIDAD | Implícita | Declarada | | | | | +----------------------+-------------------------+-------------------------+ | | | | | Variables globales | SI | SI | | | | | +----------------------+-------------------------+-------------------------+ | | | | | Variable locales | SI | SI | | | | | +----------------------+-------------------------+-------------------------+ | | | | | CASE | NO (fácl de implementar)| NO (fácl de implementar)| | | | | +----------------------+-------------------------+-------------------------+ Para su diseño, ALGOL y PL/1 pudieron aprovechar toda la experiencia por comités de trabajo de nivel mundial. Por esta razón fueron diseñados para ser versátiles y muy completos. 3.5 Conclusión ============== El diseño de arriba hacia abajo y la programación estructurada son técnicas que ha causado impacto en nuestro medio debido a que han demostrado ser un método eficiente de implementar sistemas. Como el mundo es niño aún en programación, constantemente se dan debates sobre la programación y el diseño modular; esto predice el desarrollo de técnicas cada vez más específicas para lograr mejores implementaciones de sistemas. Es importante no creer ciegamente en técnicas como esta pues, en determinadas ocasiones, puede que un diseño "amplio y desorganizado" o una programación "totalmente enredada" sea mejor que la programación estructurada y el diseño de arriba hacia abajo. 3.6 Bibliografía ================ Miller Jr. Edward F. and Lindsmood George E.: "Structured Programming", A Top-down Approach, DATAMATION, Diciembre 1973, p.55-57. Tenny Ted.: "Structured Programming in Fortran", DATAMATION, Julio 1974, p.110-115. Geller Dennis P.: "How many Directions is Top-down", DATAMATION, Junio 1976, p.109-112. Donaldson James R.: "Structured Programming", DATAMATION, Diciembre 1973, p.52-53. McCracken Daniel D.: "Revolution in Programming; an Overview", DATAMATION, Diciembre 1973, p.50-52. Inmon Bill: "An example of Structured Design", DATAMATION, Marzo 1976, p.82-86. Weinberg Gerald M., Wright Stephen E., Kauffman Richard, Goetz Martin A.: "High Level Cobol Programming", Winthrop Publishers, Inc. Cambridge, Massachusetts, 1977. Horowitz E., Sahni S.: "Fundamentals of Data Structures", Computer Science Press, Inc. 1976.