Cobol Buenas Practicas
Cobol Buenas Practicas
Cobol Buenas Practicas
“Buenas Prácticas”
Tabla de Contenidos
COMPONENTES COBOL ......................................................................................................................................................... 3
REGLAS DE APLICACIONES COBOL .................................................................................................................................. 5
BLOQUEANTES DE COBOL ...................................................................................................................................................... 5
CRITICAS DE COBOL ................................................................................................................................................................ 8
MAYORES COBOL ................................................................................................................................................................ 11
MENORES COBOL ................................................................................................................................................................ 23
INFORMATIVAS COBOL ........................................................................................................................................................ 24
Página 2 de 24
Componentes Cobol
En código Java, se trabaja con clases, métodos, librerías (.jar), etc. Estos son los objetos del lenguaje
Java. Con código Cobol, los tipos de componentes que debes conocer son:
Programa Cobol
Es un archivo de instrucciones, que se compila en un ejecutable.
Copy-Book
Es un archivo de instrucciones Cobol, que se utiliza como un ‘Include’. Equivalente de un
componente reutilizable. También se llaman ‘Copys’, porque la llamada a este archivo se hace
con una instrucción COPY.
Por ejemplo, el siguiente programa llama en la línea 65 al Copy-Book ‘MYCOPY’:
Cuando se compila el programa (en este caso, cuando lo analizamos), podemos ver que el
código del Copy-Book se insertó en el programa donde fue llamado:
Página 3 de 24
momento que tú. Es el trabajo del CICS Transaction Server de manejar esos miles de
transacciones (y otras) en paralelo.
JCL
Es un archivo batch. El JCL es un lenguaje (Job Control Language) específico, no muy fácil. Una
vez realizada tu transacción bancaria, el sistema registra una escritura contable, por ejemplo.
Pero no hay necesidad de hacerlo enseguida, lo que sería un uso innecesario de los recursos
del ordenador (CPU, memoria) cuando se necesita el mejor rendimiento para las operaciones
online. Este tratamiento se puede hacer durante la noche y este será el papel de un batch JCL.
No hay prácticamente ningún estándar de calidad para las transacciones CICS o los archivos JCL, y no
son reglas críticas, así que evitaremos un esfuerzo con pocos beneficios, de extraer y analizar estos
archivos.
Vamos a analizar los componentes Cobol, programas y Copys.
El JCL y el ‘CICs’ no son interesantes para estimar la calidad de las aplicaciones Mainframe.
Las aplicaciones Cobol
Un banco tiene de promedio aproximadamente 20 millones de líneas de Cobol. Así que no se analiza
en una sola vez. De repente, lo normal es de empezar con las aplicaciones más críticas. El problema: la
noción de aplicación no tiene sentido en Cobol.
Se trata de sistemas Legacy, que existen desde décadas, y están muy imbricados y entrelazados. Por
ejemplo, el código Cobol que te permite realizar tus transacciones bancarias usa probablemente
algunos Copy-books que también serán necesarios para el sistema de contabilidad y el batch para
grabar la escritura contable.
Ahora, es obvio que no se pueden agrupar en un solo lugar todos los archivos que constituyen los
millones de líneas de código del portafolio Cobol de la empresa. Un mainframe es un ordenador con
un sistema de archivos y los archivos se organizan en librerías o bibliotecas, el equivalente de las
carpetas en tu propio ordenador personal. Lo que vamos a analizar es el contenido de un directorio,
que vamos a extraer y descargar desde el mainframe hasta nuestra plataforma Sonar / Jenkins.
Así que no te sorprendes si en la reunión, algunos hablan de «módulos» en lugar de aplicaciones. En
cualquier caso, lo que te interesa es la forma de organizar los diferentes conjuntos de archivos en los
diferentes análisis, que se refiere a aplicaciones, módulos o cualquier otro nombre que se desea
darles.
Página 4 de 24
Reglas de Aplicaciones COBOL
Bloqueantes de COBOL
1. Las llamadas a "PERFORM" no deben ser de forma recursiva
La mayoría de los entornos COBOL no admiten llamadas PERFORM recursivas ya que esto puede
provocar resultados impredecibles. Esta regla permite reforzar esta restricción
Ejemplo:
PARAGRAPH1.
PERFORM PARAGRAPH2.
PARAGRAPH2.
PERFORM PARAGRAPH3.
PARAGRAPH3.
PERFORM PARAGRAPH1.
Ejemplo:
El siguiente fragmento de código ilustra esta regla con un umbral de 3. Cuando se alcanza PERFORM
FOURTH, el total de la cadena tiene una longitud de 4 (FIRST - SECOND -> THIRD -> FOURTH)
PERFORM FIRST.
FIRST.
PERFORM SECOND.
SECOND.
PERFORM THIRD.
THIRD.
PERFORM FOURTH.
FOURTH.
DISPLAY something.
Página 5 de 24
3. Las condiciones no deben evaluar incondicionalmente a "TRUE" o "FALSE"
Las sentencias condicionales utilizando una condición que no puede ser otra cosa que FALSO, tienen
el efecto de hacer bloques de código no funcional. Si la condición no puede evaluar nada más que lo
que sea TRUE, la sentencia condicional es completamente redundante y hace que el código sea
menos legible.
Es muy probable que el código no coincida con lo que quería el programador.
La condición puede ser eliminada o debe ser actualizada de forma que no siempre se evalúe TRUE o
FALSE.
Ejemplo
1-
* Non-Compliant: IF FOO is a numeric, its value can't be "a" at the same
time
IF FOO IS NUMERIC AND FOO = "a" DISPLAY "always false".
2-.
IF BAR = 4
* Non-Compliant: due to the nesting IF statement, we know that BAR
= 4 here and so
* the following condition is always false -> dead code
IF FOO = "a" AND BAR = 5
DISPLAY "always false"
END-IF.
...
END-IF
3-.
01 BAR PIC 9.
...
* Non-compliant: by definition BAR can't be greater than 9
IF BAR > 30 THEN DISPLAY "always false".
Página 6 de 24
Cuando se utiliza algún gestor de transacciones como IBM IMS, cada aplicación COBOL se considera
un sub-programa por el gestor de transacciones. La sentencia GOBACK devuelve el control al gestor
de la transacción, pero utilizando STOP RUN se pueden ocasionar resultados imprevisibles o realizar
alguna finalización anómala.
Ejemplo
STOP RUN
5. Las sentencias STOP RUN o "GOBACK" deben ser las últimas sentencias de una
secuencia.
Cualquier declaración después de un STOP RUN o un GOBACK es código inalcanzable y por lo tanto
código muerto que se debe eliminar.
Ejemplo
PARAGRAPH1.
MOVE A TO B.
STOP RUN.
MOVE B TO C.
Solución
PARAGRAPH1.
MOVE A TO B.
MOVE B TO C.
STOP RUN.
Página 7 de 24
Criticas de COBOL
Esta severidad es la segunda más alta de todas. Cuando en el código nos encontramos ante una regla
crítica, hay que tener en cuenta que cuando se ejecute el código, la aplicación probablemente fallará,
provocando algún tipo de excepción.
Llamadas a pilas que contienen una gran cantidad de sentencias PERFORM es un ingrediente clave
para hacer lo que se conoce como “código espagueti”. Dicho código es difícil de leer, refactorizar y
por tanto de mantener.
Esta regla soporta tanto el uso de secciones como de párrafos
Ejemplo
El siguiente fragmento de código muestra esta regla con un umbral de 3. Cuando se alcanza
PERFORM FOURTH, el total de la cadena tiene una longitud de 4 (FIRST à SECOND à THIRD à
FOURTH)
PERFORM FIRST.
FIRST.
PERFORM SECOND.
SECOND.
PERFORM THIRD.
THIRD.
PERFORM FOURTH.
FOURTH.
DISPLAY something.
Página 8 de 24
7. Valores alfanuméricos no deben moverse a campos numéricos
Un valor alfanumérico no debe ser movido a un campo numérico. Dado que los valores alfanuméricos
se almacenan de manera diferente que los valores numéricos, simplemente moviendo los bits de un
campo a otro producirá resultados extraños en el mejor de los casos, y se romperá la ejecución en el
peor.
En lugar de ello, NUMVAL se debe utilizar para convertir explícitamente el valor numérico por uno
numérico.
Ejemplo
01 MY-STR PIC X(3) VALUE SPACES.
01 MY-NUM PIC 9(3) VALUE ZEROES.
*> ...
MOVE '1' TO MY-STR
MOVE MY-STR TO MY-NUM *> Noncompliant
Solución
01 MY-STR PIC X(3) VALUE SPACES.
01 MY-NUM PIC 9(3) VALUE ZEROES.
*> ...
MOVE '1' TO MY-STR
MOVE FUNCTION NUMVAL(MY-STR) TO
MY-NUM
O
01 MY-STR PIC X(3) VALUE SPACES.
01 MY-STR-RED REDEFINES MY-STR PIC 9(3).
01 MY-NUM PIC 9(3) VALUE ZEROES.
*> ...
IF MY-STR NUMERIC
MOVE MY-STR-RED TO MY-NUM
END-IF
Página 9 de 24
No se debe evitar anidar demasiados IF, ya que hace el código más complejo y por lo tanto difícil de
mantener.
Se permite anidar hasta 5 IF
Ejemplo
PERFORM PARAGRAPH1 THRU PARAGRAPH3. > código contenido entre PARAGRAPH1
and PARAGRAPH3 ahora se considera como un modulo
EXIT PROGRAM.
PARAGRAPH1.
MOVE A TO B.
IF SOMETHING
GO TO PARAGRAPH3 >OK
END-IF.
IF SOMETHING-ELSE
GO TO PARAGRAPH4 >NOK a medida que dejamos el módulo llamado con
"PERFORM PARGRAPH1 THRU PARAGRAPH3" statement
END-IF.
PARAGRAPH2.
MOVE A TO B.
PARAGRAPH3.
EXIT.
PARAGRAPH4.
10. Los valores solo se deben mover a variables lo suficientemente grandes que no se
trunquen
Mover un valor grande dentro de un campo pequeño dará lugar a un truncamiento de los datos para
ambos valores, numéricos y alfabéticos. En general, los valores alfabéticos se truncan por la derecha
Página 10 de 24
mientras que los valores numéricos se truncan por la izquierda. Sin embargo, en el caso de los valores
de coma flotante, cuando el destino tiene menos precisión para mantener el valor donde va a ser
movido, los decimales serán truncados, no redondeados, desde la derecha.
En cualquier caso, la pérdida de datos es siempre el resultado cuando los valores demasiado grandes
se mueven a campos demasiado pequeños
Ejemplo
Solución
01 NUM-A PIC 9(3)V99.
01 ALPHA PIC X(15).
*> ...
Mayores COBOL
Página 11 de 24
Las reglas con severidad mayor hay que empezar a tenerlas en cuenta, ya que implican errores
potenciales en las aplicaciones y malos hábitos que no deberían emplearse en el desarrollo.
Ejemplo
DISPLAY "hello world"
El uso de DISTINCT en sentencias SQL SELECT se debe evitar. No es solo que el comando no es
eficiente para quitar duplicados, pero la consulta SELECT DISTINCT indica que algo no se está
haciendo del todo bien. Eso es porque el uso de la palabra reservada DISTINCT significa que los datos
redundantes se están guardando en la base de datos y se están descartando después.
Tener lógica condicional dentro de una sentencia WHEN, a menudo lleva a sentencias de evaluación
grandes y difíciles de leer. En muchos casos, la presencia de lógica condicional indica que el bloque
de código dentro de la cláusula WHEN debe ser dividido.
En el momento en que una sentencia contiene sentencias anidadas, podría llegar a ser difícil ver las
sentencias que están anidadas y cuáles no. Es por eso que es aconsejable terminar una lista de
sentencias anidadas con END-${STATEMENT-NAME}
Ejemplo
READ DF-PARAM-SPILOTE AT END
GO TO F-LECT-SPILOTE.
Solución
READ DF-PARAM-SPILOTE AT END
GO TO F-LECT-SPILOTE
END-READ.
Parámetros
A continuación, mostramos la lista de parámetros sobre los que se puede o no tener en cuenta la
regla y su valor por defecto.
Página 12 de 24
PARÁMETRO VALOR POR DEFECTO
ADD TRUE
CALL TRUE
DIVIDE TRUE
EVALUATE TRUE
IF TRUE
MULTIPLY TRUE
PERFORM TRUE
READ TRUE
SEARCH TRUE
STRING TRUE
SUBSTRACT TRUE
UNSTRING TRUE
WRITE TRUE
La sentencia DISPLAY…UPON CONSOLE envía información a la consola, por lo que requiere una
intervención del operador. Esto debe reservarse solo para fines de debug.
Página 13 de 24
16. Evite programas con demasiada complejidad ciclomática
El número de operandos distintos de una condición (IF, EVALUATE, …) no debe superar un umbral
definido.
El umbral definido actualmente es 3
Ejemplo
* Compliant, 3 operands are found
IF WS-FOO(1) = 1 OR
WS-FOO(2) = 2 OR
WS-FOO(3) = 3 OR
WS-BAR = 4 OR
WS-BAZ = 42
END-IF.
Solución
* Non-Compliant, 4 operands are found, higher than the maximum
allowed 3
IF WS-FOO(1) = 1 OR
WS-FOO(2) = 2 OR
WS-FOO(3) = 3 OR
WS-BAR = 4 OR
WS-BAZ = 5 OR
WS-QUX = 42
END-IF.
Página 14 de 24
18. Evitar usar la sentencia "NEXT SENTENCE".
Se debe evitar el uso de la sentencia NEXT SENTENCE ya que rompe el flujo de ejecución del proceso
y es propenso a errores, ya que no define exactamente dónde ir. Se debe utilizar la sentencia
CONTINUE en su lugar.
Ejemplo
IF CONDITION1 THEN
IF CONDITION2 THEN
...
END-IF
END-IF.
Solución
IF CONDITION1 AND CONDITION2 THEN
...
END-IF.
Página 15 de 24
20. Los COPYBOOKS se deben utilizar solo para compartir estructuras de datos, pero no
lógica.
Modificar los procedimientos de los copybooks puede causar problemas potenciales cuando muchos
programas se juntan en la compilación. El tener que editar los procedimientos constantemente
provoca retrasos en el mantenimiento ya que los desarrolladores tienen que esperar a que otro
desarrollador termine el trabajo. Esto muchas veces ocasiona el doble de trabajo cuando los
programas no están sincronizados y un cambio reciente puede ser peligrosamente perdido en el
programa.
Ejemplo
PROCEDURE DIVISION.
...
COPY MY_COPYBOOK. <- No conforme
...
Solución
PROCEDURE DIVISION.
...
CALL MY_MACRO. <- Conforme
...
22. Las palabras de finalización como "END-IF", "END-READ", ... deben alinearse con su
correspondiente "IF", "READ”, ...
La alineación de las sentencias de apertura y cierre es fundamental para mantener el código legible,
especialmente cuando los bloques contienen declaraciones anidadas.
En las sentencias IF, la regla también comprueba la alineación de la palabra ELSE.
Ejemplo
IF SOME-STATUS = 1
DISPLAY something
END-IF.
Solución
Página 16 de 24
IF SOME-STATUS = 1
DISPLAY something
END-IF.
Información adicional
La regla se puede configurar para que realice las comprobaciones sobre las siguientes sentencias. Por
defecto se evalúan todas, pero se puede configurar para evitar algunas de estas:
ACCEPT
ADD
CALL
COMPUTE
DELETE
DISPLAY
DIVIDE
EVALUATE
EXECDLI
IF
MOVE
MULTIPLY
PERFORM
READ
RETURN
REWRITE
SEARCH
START
STRING
SUBSTRACT
UNSTRING
WRITE
XMLGENERATE
XMLPARSE
Página 17 de 24
Ejemplo
*> No conforme
EXEC SQL
SELECT * FROM my_table1 WHERE
my_column1 IN
(SELECT my_column2 FROM my_table2
WHERE my_column3 IN
(SELECT my_column4 FROM my_table3))
END-EXEC.
Solución
EXEC SQL
SELECT * FROM my_table
END-EXEC.
Ejemplo
OPEN INPUT my-file
Solución
OPEN INPUT my-file
...
CLOSE my-file
Cada sección debe ser comentada para explicar su objetivo y cómo funciona. El comentario se puede
escribir justo antes o justo después de la etiqueta de la sección.
Página 18 de 24
Ejemplo
UNCOMMENTED-SECTION SECTION.
Solución
* Some comments
CORRECTLY-COMMENTED-SECTION SECTION.
ANOTHER-CORRECTLY-COMMENTED-SECTION SECTION.
* Some comments
30. Dos ramas en la misma estructura condicional no deben tener exactamente la misma
implementación.
Tener dos sentencias WHEN en la misma sentencia EVALUATE o dos ramas en la misma estructura IF
con la misma implementación, en el mejor caso es código duplicado y en el peor es un error de
codificación. Si la misma lógica es necesaria para ambos casos, entonces deberían estar combinados,
para una estructura IF o si el código debe caer de un WHEN a otro en la misma sentencia EVALUATE.
Ejemplo
EVALUATE X
WHEN 1
PERFORM SECTION1
WHEN 2
PERFORM SECTION2
WHEN 3 *> No conforme; duplicado WHEN 1's
implementación
PERFORM SECTION1
END-EVALUATE.
IF X = 1
PERFORM SECTION1
ELSE
IF X > 10
PERFORM SECTION2
Página 19 de 24
ELSE *> no conforme
PERFORM SECTION1
END-IF
END-IF.
Solución
EVALUATE X
WHEN 1
WHEN 3
PERFORM SECTION1
WHEN 2
PERFORM SECTION2
END-EVALUATE.
IF X = 1 OR X <= 10
PERFORM SECTION1
ELSE
PERFORM SECTION2
END-IF.
O
EVALUATE X
WHEN 1
PERFORM SECTION1
WHEN 2
PERFORM SECTION2
WHEN 3
PERFORM SECTION3
END-EVALUATE.
IF X = 1
PERFORM SECTION1
ELSE
IF X > 10
PERFORM SECTION2
ELSE
PERFORM SECTION3
Página 20 de 24
END-IF
END-IF.
Ejemplo
IDENTIFICATION DIVISION.
PROGRAM-ID. foo.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 PERSON PIC X(42). *> Compatible con el elemento de
datos secundario FIRST_NAME se utiliza
02 FIRST_NAME PIC X(21).
02 LAST_NAME PIC X(21).
PROCEDURE DIVISION.
32. Los párrafos sin usar se deben eliminar (código potencialmente muerto)
Un párrafo sin usar nunca se llama explícitamente con la ayuda de las sentencias GO TO o PERFORM.
Solo hay dos razones para tener ese párrafo:
Realmente no se utiliza y en ese caso se puede eliminar
Solo se utiliza como un comentario para delimitar claramente un bloque de código y esto es
una mala práctica
La acción para solucionar esto debe ser:
Página 21 de 24
Sustituir el párrafo por una línea de comentario
Refactorizar el código para hacer una llamada explícita al párrafo en lugar de dejar que el
flujo de ejecución lo llame implícitamente
Ejemplo
A010-PRINCIPAL.
EVALUATE Y5FTAR-PER-ECN-CTS
WHEN '01'
MOVE 'A' TO WS-CD-PER-CTS
WHEN '02'
MOVE 'S' TO WS-CD-PER-CTS
WHEN '04'
MOVE 'T' TO WS-CD-PER-CTS
END-EVALUATE.
Solución
A010-PRINCIPAL.
EVALUATE Y5FTAR-PER-ECN-CTS
WHEN '01'
MOVE 'A' TO WS-CD-PER-CTS
WHEN '02'
MOVE 'S' TO WS-CD-PER-CTS
WHEN '04'
MOVE 'T' TO WS-CD-PER-CTS
WHEN OTHER
MOVE 'M' TO WS-CD-PER-CTS
END-EVALUATE.
Página 22 de 24
34. Cuando se llama a un subprograma, el elemento de datos que contiene el nombre
del subprograma que será llamado no debe ser actualizado mediante programación
Definir un subprograma para ser llamado en tiempo de ejecución es posible, pero está desaconsejado.
Esta característica muy potente puede ser fácilmente mal utilizada e incluso cuando se utiliza
correctamente, aumenta la complejidad ciclomática general del programa y hace imposible antes de
la ejecución saber exactamente lo que va a ser ejecutado. Por lo tanto, la definición del subprograma
que será llamado en tiempo de ejecución es una característica que debe ser evitada.
Ejemplo
MOVE SOMETHING TO MY_SUBPROG.
...
CALL MY_SUBPROG.
Solución
01 MY_SUBPROG PIC X(10) VALUE "SUB123".
…
CALL MY_SUBPROG.
O
CALL "MY_SUBPROG".
Menores COBOL
Es la segunda severidad más baja de todas. Son aquellas reglas que no tienen mucho impacto en el código o
no provocan grandes fallos, pero que deberían empezar a tenerse en cuenta para mejorar la calidad del
código y aprender buenas prácticas de desarrollo.
Página 23 de 24
Los programadores no deben comentar el código, ya que aumenta el tamaño de las aplicaciones y
reduce la legibilidad. El código no utilizado debe eliminarse y puede ser recuperado de los sistemas de
gestión de versiones, en caso de ser necesario. Para evitar la generación de algunos falsos positivos,
esta regla desencadena una evidencia en un bloque de comentarios de código si:
Al menos 3 líneas se identifican como potenciales líneas de código (empiezan por una palabra
reservada de COBOL
Al menos el 20% de todas las líneas del bloque de comentarios se identifica como algunas
posibles líneas de código
Informativas COBOL
Es la severidad más baja de todas. Son aquellas reglas que sería bueno cumplir, pues se trata de aspectos que
dan más consistencia al código, aunque no son fundamentales.
Página 24 de 24