Programación estructurada Jackson - Jackson structured programming

Ejemplo de diagrama JSP.

La programación estructurada de Jackson ( JSP ) es un método para la 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 . La técnica de JSP es 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 forma 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 diagraman 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. Él documentó el sistema en su libro de 1975 Principles of Program Design . En una charla de la conferencia de 2001, proporcionó un análisis retrospectivo de las fuerzas impulsoras originales detrás del método y lo relacionó con los desarrollos posteriores de la 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 usar para diseñar programas para cualquier lenguaje de programación que tenga construcciones de control estructuradas: secuencia, iteración y selección ("si / entonces / si no") .

La programación estructurada de Jackson era similar a la programación estructurada de Warnier / Orr, aunque JSP consideró estructuras de datos de entrada y salida, mientras que el método Warnier / Orr se centró casi exclusivamente en la estructura del flujo de salida.

Motivación por el método

En el momento 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 lee su archivo de entrada como una secuencia de registros, de modo que todos los programas tienen la misma estructura: un único bucle principal que procesa todos los registros del archivo, uno a la vez. Jackson afirmó que esta estructura de programa casi siempre era incorrecta y alentó a los programadores a buscar estructuras de datos más complejas. En el Capítulo 3 de Principios de diseño de programas, Jackson presenta dos versiones de un programa, una diseñada con JSP y la otra con la estructura tradicional de bucle único. 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 enumere cada registro y el número de veces que ocurre en el archivo.

Aquí está la versión tradicional de un solo ciclo del programa.

String line;
int count = 0;
String firstLineOfGroup = null;

// begin single main loop
while ((line = in.readLine()) != null) {
    if (firstLineOfGroup == null || !line.equals(firstLineOfGroup)) {
        if (firstLineOfGroup != null) {
            System.out.println(firstLineOfGroup + " " + count);
        }
        count = 0;
        firstLineOfGroup = line;
    }
    count++;
}
if (firstLineOfGroup != null) {
    System.out.println(firstLineOfGroup + " " + count);
}

Aquí hay una versión estilo JSP del mismo programa. Tenga en cuenta que (a diferencia del programa tradicional) tiene dos bucles, uno anidado dentro del otro. El ciclo externo procesa grupos de registros repetidos, mientras que el ciclo interno procesa los registros individuales en un grupo.

String line;
int numberOfLinesInGroup;

line = in.readLine();
// begin outer loop: process 1 group
while (line != null) {  
    numberOfLinesInGroup = 0;
    String firstLineOfGroup = line;

    // begin inner loop: process 1 record in the group
    while (line != null && line.equals(firstLineOfGroup)) {
        numberOfLinesInGroup++;
        line = in.readLine();
    }
    System.out.println(firstLineOfGroup + " " + numberOfLinesInGroup);
}

Jackson critica la versión tradicional de bucle único por no 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 que funcione correctamente, se ve obligado a incluir un código especial para manejar el primer y último registro del archivo.

El metodo basico

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

La intención es crear programas que sean fáciles de modificar durante su vida útil. La principal idea de Jackson fue que los cambios en los requisitos suelen ser ajustes menores a las estructuras existentes. Para un programa construido usando JSP, las entradas, las salidas y las estructuras internas del programa coinciden, por lo que los pequeños cambios en las entradas y salidas deben traducirse en pequeños cambios en el programa.

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

  • operaciones fundamentales
  • secuencias
  • iteraciones
  • trozos escogidos

El método comienza describiendo las entradas de un programa en términos de los cuatro tipos de componentes fundamentales. Luego pasa a describir los resultados 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 para aplicaciones de computación intensiva, como el procesamiento de señales digitales (DSP), también es necesario dibujar diagramas de estructura de algoritmos, que se centren 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 salidas. Algunos programas procesan toda la entrada antes de realizar cualquier salida, mientras que otros leen en un registro, escriben un registro e iteran. Estos enfoques deben reflejarse en el PSD.

El PSD, que es un lenguaje neutro, 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 forma útil el flujo de control dentro de los métodos de una clase.

JSP utiliza una notación de diagramación 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 simple se dibuja como una caja.

Una caja con la etiqueta 'A'
Una operación

Una secuencia de operaciones está representada por cuadros conectados con líneas. En el siguiente ejemplo, A es una secuencia que consta de las operaciones B, C y D.

Una caja etiquetada como 'A' conectada a tres cajas debajo de ella etiquetadas como 'B', 'C' y 'D'
Una secuencia

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

Un cuadro con la etiqueta 'A' conectado a un cuadro con la etiqueta 'B' debajo con una estrella en la esquina superior derecha
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 caja etiquetada como 'A' conectada a tres cajas debajo de ella etiquetadas como 'B', 'C' y 'D' cada una con un círculo en la esquina superior derecha
Una selección

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

Un ejemplo trabajado

Como ejemplo, así es como 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 una secuencia de bytes que puede verse como ocurriendo 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 el número de veces que ese valor se repitió en la ejecución. Por ejemplo, una serie de ocho apariciones 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 forma burda.

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

JSP RLE input.png

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

Salida JSP RLE1.png

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

Correspondencia JSP RLE.png

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).

Programa JSP RLE.png

Una vez que la estructura del programa está terminada, el programador crea una lista de las operaciones computacionales que el programa debe realizar, y el diagrama de la 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 incrementos
  5. salida recordada byte
  6. contador de salida

Además, en esta etapa, las condiciones sobre iteraciones (bucles) y selecciones (si-entonces-si no o declaraciones de caso) se enumeran y se agregan al diagrama de estructura del programa.

  1. mientras haya más bytes
  2. mientras hay más bytes y este byte es el mismo que el primer byte de la ejecución y el recuento aún cabe en un byte

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

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int c;
    int first_byte;
    int count;

    c = getchar();   /* get first byte */
    while (c != EOF) {
        /* process the first byte in the run */
        first_byte = c;
        count = 1;
        c = getchar();   /* get next byte */

        /* process the succeeding bytes in the run */
        while (c != EOF && c == first_byte && count < 255) {
            /* process one byte of the same value */
            count++;
            c = getchar();   /* get next byte */
        }

        putchar(first_byte);
        putchar(count);
    }
    return EXIT_SUCCESS;
}

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

En Principios del diseño de programas, Jackson reconoció situaciones que plantean 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 perversos" estándar era cómo diseñar un programa de procesamiento de transacciones. En tal programa, un archivo secuencial de registros de actualización se ejecuta contra un archivo maestro secuencial, produciendo un archivo maestro actualizado como salida. (Por ejemplo, por la noche, un banco ejecutaba un programa por lotes que actualizaba los saldos en las cuentas de sus clientes en función de los registros de los depósitos y retiros que habían realizado ese día). Los principios de diseño de programas proporcionaban 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 involucró lo que Jackson llamó "dificultades de reconocimiento" y hoy llamaríamos problemas de análisis. La técnica básica de diseño JSP se complementó con operaciones POSIT y QUIT para permitir el diseño de lo que ahora llamaríamos un analizador de retroceso.

JSP también reconoció tres situaciones que se denominan "choques de estructura" - un choque de límites, un choque de ordenamiento y un choque entrelazado - y proporcionó técnicas para tratar con ellos. 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. En efecto, es necesario escribir dos programas: el primero procesa el flujo de entrada, lo divide en partes más pequeñas y las escribe en un archivo intermedio. El segundo programa lee el archivo intermedio y produce la salida deseada.

Diseño JSP y orientado a objetos

JSP se desarrolló mucho antes de que las tecnologías orientadas a objetos estuvieran disponibles. Ni él ni su método sucesor JSD tratan lo que ahora se llamaría "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 .

Ver también

Referencias

enlaces externos