stringtranslate.com

Programación estructurada de Jackson

Ejemplo de un diagrama JSP.

La programación estructurada de Jackson ( JSP ) es un método de programación estructurada desarrollado por el consultor de software británico Michael A. Jackson y descrito en su libro de 1975 Principles of Program Design . [1] La técnica de JSP consiste en analizar las estructuras de datos de los archivos que un programa debe leer como entrada y producir como salida, y luego producir un diseño de programa basado en esas estructuras de datos, de modo que la estructura de control del programa maneje esas estructuras de datos de una manera natural e intuitiva.

JSP describe estructuras (tanto de datos como de programas) utilizando tres estructuras básicas: secuencia, iteración y selección (o alternativas). Estas estructuras se representan en diagramas como (en efecto) una representación visual de una expresión regular .

Introducción

Michael A. Jackson desarrolló originalmente JSP en la década de 1970. Documentó el sistema en su libro Principles of Program Design (Principios de diseño de programas) de 1975. [1] En una conferencia de 2001, [2] proporcionó un análisis retrospectivo de las fuerzas impulsoras originales detrás del método y lo relacionó con desarrollos posteriores de ingeniería de software. El objetivo de Jackson era hacer que los programas de procesamiento de archivos por lotes COBOL fueran más fáciles de modificar y mantener, pero el método se puede utilizar para diseñar programas para cualquier lenguaje de programación que tenga construcciones de control estructuradas: secuencia, iteración y selección ("if/then/else").

La programación estructurada de Jackson era similar a la programación estructurada de Warnier/Orr [3] [4] aunque JSP consideraba tanto las estructuras de datos de entrada como de salida, mientras que el método Warnier/Orr se centraba casi exclusivamente en la estructura del flujo de salida.

Motivación para el método

En la época en que se desarrolló JSP, la mayoría de los programas eran programas COBOL por lotes que procesaban archivos secuenciales almacenados en cinta. Un programa típico leía su archivo de entrada como una secuencia de registros, de modo que todos los programas tenían la misma estructura: un único bucle principal que procesaba todos los registros del archivo, uno a la vez. Jackson afirmó que esta estructura de programa casi siempre era errónea y alentó a los programadores a buscar estructuras de datos más complejas. En el Capítulo 3 de Principles of Program Design [1], Jackson presenta dos versiones de un programa, una diseñada con JSP y la otra con la estructura tradicional de un solo bucle. Aquí está su ejemplo, traducido de COBOL a Java. El propósito de estos dos programas es reconocer grupos de registros repetidos (líneas) en un archivo ordenado y producir un archivo de salida que incluya cada registro y la cantidad de veces que aparece en el archivo.

A continuación se muestra la versión tradicional de un solo bucle del programa.

Cadena línea ; int count = 0 ; Cadena firstLineOfGroup = null ;       // comienza un bucle principal único mientras ( ( linea = in.readLine ( ) ) != null ) { si ( firstLineOfGroup == null || ! linea.equals ( firstLineOfGroup )) { si ( firstLineOfGroup ! = null ) { System.out.println ( firstLineOfGroup + " " + count ) ; } count = 0 ; firstLineOfGroup = linea ; } count ++ ; } si ( firstLineOfGroup ! = null ) { System.out.println ( firstLineOfGroup + " " + count ) ; }                                         

A continuación se muestra una versión del mismo programa en estilo JSP. Observe que (a diferencia del programa tradicional) tiene dos bucles, uno anidado dentro del otro. El bucle externo procesa grupos de registros repetidos, mientras que el bucle interno procesa los registros individuales de un grupo.

Cadena línea ; int numberOfLinesInGroup ;  línea = en . readLine (); // comienza el bucle externo: procesa 1 grupo mientras ( línea != null ) { numberOfLinesInGroup = 0 ; String firstLineOfGroup = línea ;               // comienza el bucle interno: procesa 1 registro en el grupo while ( line != null && line . equals ( firstLineOfGroup )) { numberOfLinesInGroup ++ ; line = in . readLine (); } System . out . println ( firstLineOfGroup + " " + numberOfLinesInGroup ); }                 

Jackson critica la versión tradicional de un solo bucle por no poder procesar la estructura del archivo de entrada (grupos repetidos de registros que contienen registros individuales repetidos) de forma natural. Una señal de su diseño antinatural es que, para funcionar correctamente, se ve obligado a incluir un código especial para manejar el primer y el último registro del archivo.

El método básico

JSP utiliza pasos semiformales para capturar la estructura existente de las entradas y salidas de un programa en la estructura del programa mismo.

La intención es crear programas que sean fáciles de modificar a lo largo de su vida útil. La principal idea de Jackson fue que los cambios de requisitos suelen ser pequeños retoques a las estructuras existentes. En el caso de un programa creado con JSP, las entradas, las salidas y las estructuras internas del programa coinciden, por lo que pequeños cambios en las entradas y las salidas deberían traducirse en pequeños cambios en el programa.

JSP estructura los programas en términos de cuatro tipos de componentes:

El método comienza describiendo las entradas de un programa en términos de los cuatro tipos de componentes fundamentales. Luego pasa a describir las salidas del programa de la misma manera. Cada entrada y salida se modela como un diagrama de estructura de datos (DSD) independiente. Para que JSP funcione en aplicaciones con uso intensivo de recursos computacionales, como el procesamiento de señales digitales (DSP), también es necesario dibujar diagramas de estructura de algoritmos, que se centran en las estructuras de datos internas en lugar de las de entrada y salida.

Las estructuras de entrada y salida se unifican o fusionan en una estructura de programa final, conocida como diagrama de estructura de programa (PSD). Este paso puede implicar la adición de una pequeña cantidad de estructura de control de alto nivel para unir las entradas y las salidas. Algunos programas procesan todas las entradas antes de generar ninguna salida, mientras que otros leen un registro, escriben otro registro y repiten. Estos enfoques deben reflejarse en el PSD.

El PSD, que es neutral en cuanto al lenguaje, se implementa luego en un lenguaje de programación. JSP está orientado a la programación a nivel de estructuras de control, por lo que los diseños implementados utilizan solo operaciones primitivas, secuencias, iteraciones y selecciones. JSP no se utiliza para estructurar programas a nivel de clases y objetos, aunque puede estructurar de manera útil el flujo de control dentro de los métodos de una clase.

JSP utiliza una notación de diagrama para describir la estructura de entradas, salidas y programas, con elementos de diagrama para cada uno de los tipos de componentes fundamentales.

Una operación sencilla se dibuja en forma de cuadro.


Una operación

Una secuencia de operaciones se representa mediante casillas conectadas con líneas. En el ejemplo siguiente, A es una secuencia que consta de las operaciones B, C y D.


Una secuencia

Una iteración se representa nuevamente con cuadros unidos. Además, la operación iterada tiene una estrella en la esquina superior derecha de su cuadro. En el ejemplo siguiente, A es una iteración de cero o más invocaciones de la operación B.


Una iteración

La selección es similar a una secuencia, pero con un círculo dibujado en la esquina superior derecha de cada operación opcional. En el ejemplo, A es una selección de una y solo una de las operaciones B, C o D.


Una selección

Tenga en cuenta que en los diagramas anteriores, el elemento A es la secuencia o iteración, no los elementos B, C o D (que en los diagramas anteriores son todos elementales). Jackson ofrece la "regla de mirar hacia abajo" para determinar qué es un elemento, es decir, observe los elementos que se encuentran debajo de un elemento para averiguar cuál es.

Un ejemplo práctico

A modo de ejemplo, aquí se muestra cómo un programador JSP diseñaría y codificaría un codificador de longitud de ejecución . Un codificador de longitud de ejecución es un programa cuya entrada es un flujo de bytes que se puede ver como si ocurriera en ejecuciones , donde una ejecución consiste en una o más ocurrencias de bytes del mismo valor. La salida del programa es un flujo de pares de bytes, donde cada par de bytes es una descripción comprimida de una ejecución. En cada par, el primer byte es el valor del byte repetido en una ejecución y el segundo byte es un número que indica la cantidad de veces que ese valor se repitió en la ejecución. Por ejemplo, una ejecución de ocho ocurrencias de la letra "A" en el flujo de entrada ("AAAAAAAA") produciría "A8" como un par de bytes en el flujo de salida. Los codificadores de longitud de ejecución se utilizan a menudo para comprimir mapas de bits de manera rudimentaria.

Con JSP, el primer paso es describir las estructuras de datos de los flujos de entrada de un programa. El programa tiene un solo flujo de entrada, que consta de cero o más ejecuciones del mismo valor de byte. Aquí se muestra el diagrama de la estructura de datos de JSP para el flujo de entrada.

El segundo paso es describir la estructura de datos de salida, que en este caso consta de cero o más iteraciones de pares de bytes.

El siguiente paso es describir las correspondencias entre los componentes de las estructuras de entrada y salida.

El siguiente paso es utilizar las correspondencias entre las dos estructuras de datos para crear una estructura de programa que sea capaz de procesar la estructura de datos de entrada y producir la estructura de datos de salida. (A veces esto no es posible. Consulte la discusión sobre conflictos de estructuras a continuación).

Una vez finalizada la estructura del programa, el programador crea una lista de las operaciones computacionales que el programa debe realizar y el diagrama de estructura del programa se completa colgando esas operaciones de los componentes estructurales apropiados.

  1. leer un byte
  2. recordar byte
  3. Poner el contador a cero
  4. contador de incremento
  5. salida del byte recordado
  6. contador de salida

Además, en esta etapa se enumeran las condiciones de las iteraciones (bucles) y las selecciones (declaraciones if-then-else o case) y se agregan al diagrama de estructura del programa.

  1. mientras haya más bytes
  2. mientras haya más bytes y este byte sea el mismo que el primer byte de la ejecución y el conteo aún cabrá en un byte

Una vez terminado el diagrama, se puede traducir al lenguaje de programación que se esté utilizando. Aquí se muestra una traducción al lenguaje C.

#include <stdio.h> #include <stdlib.h>  int principal ( int argc , char * argv []) { int c ; int primer_byte ; int conteo ;           c = getchar (); /* obtener el primer byte */ while ( c != EOF ) { /* procesar el primer byte en la ejecución */ first_byte = c ; count = 1 ; c = getchar (); /* obtener el siguiente byte */                    /* procesar los bytes sucesivos en la ejecución */ while ( c != EOF && c == first_byte && count < 255 ) { /* procesar un byte del mismo valor */ count ++ ; c = getchar (); /* obtener el siguiente byte */ }                     putchar ( primer_byte ); putchar ( recuento ); } return EXIT_SUCCESS ; }    

Técnicas para manejar problemas de diseño difíciles

En Principios de diseño de programas, Jackson reconoció situaciones que planteaban tipos específicos de problemas de diseño y proporcionó técnicas para manejarlos.

Una de estas situaciones es un caso en el que un programa procesa dos archivos de entrada, en lugar de uno. En 1975, uno de los "problemas complejos" habituales era cómo diseñar un programa de procesamiento de transacciones. En un programa de este tipo, se ejecuta un archivo secuencial de registros de actualización frente a un archivo maestro secuencial, lo que produce un archivo maestro actualizado como salida. (Por ejemplo, por la noche un banco ejecutaría un programa por lotes que actualizaría los saldos de las cuentas de sus clientes basándose en los registros de los depósitos y retiros que habían realizado ese día). Principles of Program Design proporcionó una solución estándar para ese problema, junto con una explicación de la lógica detrás del diseño.

Otro tipo de problema implicaba lo que Jackson llamó "dificultades de reconocimiento" y que hoy llamaríamos problemas de análisis. La técnica básica de diseño de JSP se complementó con las operaciones POSIT y QUIT para permitir el diseño de lo que ahora llamaríamos un analizador sintáctico con seguimiento hacia atrás.

JSP también reconoció tres situaciones que se denominan "conflictos de estructura": un conflicto de límites, un conflicto de ordenación y un conflicto de intercalación, y proporcionó técnicas para abordarlas. En situaciones de conflicto de estructura, las estructuras de datos de entrada y salida son tan incompatibles que no es posible producir el archivo de salida a partir del archivo de entrada. Es necesario, en efecto, escribir dos programas: el primero procesa el flujo de entrada, lo divide en fragmentos más pequeños y escribe esos fragmentos en un archivo intermedio. El segundo programa lee el archivo intermedio y produce el resultado deseado.

JSP y diseño orientado a objetos

JSP se desarrolló mucho antes de que las tecnologías orientadas a objetos estuvieran disponibles. Este y su método sucesor JSD no tratan lo que ahora se denominarían "objetos" como colecciones de métodos más o menos independientes. En cambio, siguiendo el trabajo de CAR Hoare , JSP y JSD describen los objetos de software como co-rutinas . [5] [6]

Véase también

Referencias

  1. ^ abc Jackson, MA (1975), Principios del diseño de programas , Academic.
  2. ^ Jackson, MA (2001), JSP in Perspective (PDF) , Conferencia de pioneros de sd&m, Bonn, junio de 2001, archivado (PDF) del original el 16 de mayo de 2017 , consultado el 26 de enero de 2017{{citation}}: CS1 maint: ubicación ( enlace ) CS1 maint: ubicación del editor faltante ( enlace )
  3. ^ Warnier, JD (1974), Construcción lógica de programas , Nueva York: Van Nostrand Reinhold
  4. ^ Orr, KT (1980), "Programación estructurada en los años 1980", Actas de la Conferencia Anual de la ACM de 1980 , Nueva York, NY: ACM Press, págs. 323-26, doi :10.1145/800176.809987, ISBN 978-0897910286, Número de identificación del sujeto  26834496
  5. ^ Wieringa, R (diciembre de 1998), "Un estudio de métodos y técnicas de especificación de software estructurado y orientado a objetos", Comput Surv , 30 (4): 459–527, CiteSeerX 10.1.1.107.5410 , doi :10.1145/299917.299919, S2CID  14967319 .
  6. ^ Henderson-Sellers, Brian ; Edwards, JM (septiembre de 1990), "El ciclo de vida de los sistemas orientados a objetos", Communications of the ACM , 33 (9): 142–59, doi : 10.1145/83880.84529 , S2CID  14680399.

Enlaces externos