☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

Mostrar mensagens com a etiqueta REDEFINES. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta REDEFINES. Mostrar todas as mensagens

quinta-feira, 26 de setembro de 2024

O Guia Definitivo de Boas Práticas para Declarar Variáveis em COBOL Mainframe como os Grandes Bancos Fazem

 

Bellacosa Mainframe e o data division sem misterios

☕ Um Café no Bellacosa Mainframe

Data Division sem Mistérios

O Guia Definitivo de Boas Práticas para Declarar Variáveis em COBOL Mainframe como os Grandes Bancos Fazem

"Um programa COBOL raramente falha porque alguém escreveu um IF errado. Ele costuma falhar porque alguém declarou uma variável errada há vinte anos."


Introdução

Existe um velho ditado entre programadores de mainframe:

"O Procedure Division executa. A Data Division pensa."

Pode parecer exagero, mas basta passar alguns meses trabalhando em um grande banco para perceber que isso é verdade.

Quando um programa COBOL possui milhares de linhas, dezenas de interfaces, centenas de arquivos VSAM, tabelas DB2, chamadas CICS e APIs REST, o verdadeiro segredo não está apenas na lógica.

Está na organização dos dados.

É justamente por isso que os maiores bancos brasileiros possuem padrões extremamente rígidos para a Data Division.

Em muitos lugares, uma variável mal declarada simplesmente não passa pela revisão de código.

Neste artigo vamos aprender como profissionais experientes organizam suas variáveis, entender o motivo dessas regras existirem e descobrir como escrever programas que continuam fáceis de manter mesmo depois de décadas.

Pegue seu café.

Vamos organizar nossa memória principal.


Antes de falar de variáveis...

Imagine construir um prédio.

Você pode contratar o melhor pedreiro do mundo.

Se o engenheiro desenhar uma planta ruim, o prédio será um caos.

No COBOL acontece exatamente isso.

A Data Division é a planta do edifício.

A Procedure Division apenas utiliza aquilo que foi planejado.

Quanto melhor for sua estrutura de dados, mais simples será escrever toda a lógica do programa.


A filosofia dos grandes bancos

Em bancos, normalmente existem padrões semelhantes a estes:

  • nomes padronizados

  • agrupamentos claros

  • nenhuma variável "solta"

  • documentação implícita

  • facilidade para debug

  • facilidade para manutenção

  • reaproveitamento

O objetivo nunca é escrever menos.

É escrever melhor.


A estrutura clássica

Normalmente encontramos algo parecido.

WORKING-STORAGE SECTION.

01 WS-CONTROLE.

01 WS-ENTRADA.

01 WS-SAIDA.

01 WS-CALCULOS.

01 WS-INDICADORES.

01 WS-CONSTANTES.

01 WS-TABELAS.

01 WS-AREAS-DE-TRABALHO.

Só olhando os nomes já sabemos onde procurar qualquer informação.

Essa organização economiza horas de manutenção.


Prefixos fazem diferença

Um dos maiores erros de iniciantes é escrever:

01 NOME.
01 CPF.
01 IDADE.
01 TOTAL.

Imagine um programa com 8.000 variáveis.

Boa sorte.

Os grandes bancos normalmente utilizam prefixos.

WS-NOME
WS-CPF
WS-IDADE
WS-TOTAL

WS significa:

Working Storage.

Quando existem outras áreas:

LK-
DFHCOMMAREA
LS-
CS-
SQL-

Exemplo:

WS-CLIENTE

LK-CLIENTE

LS-CLIENTE

SQL-CLIENTE

Cada uma pertence a uma área diferente.

O nome já explica sua origem.


Nunca use nomes genéricos

Evite:

WS-AUX

WS-TEMP

WS-X

WS-DADOS

WS-AREA

WS-TESTE

Isso não explica absolutamente nada.

Prefira:

WS-SALDO-ATUAL

WS-VALOR-LIMITE

WS-TOTAL-PARCELAS

WS-QTD-CLIENTES

WS-DATA-PROCESSAMENTO

Quem ler o programa daqui a vinte anos agradecerá.


O padrão VERBO + OBJETO

Muitos bancos gostam de indicar o significado da variável.

Exemplo:

WS-QTD-PRODUTOS

WS-VLR-TOTAL

WS-DT-NASCIMENTO

WS-HR-PROCESSAMENTO

WS-FL-ATIVO

WS-CD-AGENCIA

WS-NR-CONTA

Observe as abreviações.

PrefixoSignificado
DTData
HRHora
FLFlag
CDCódigo
NRNúmero
QTDQuantidade
VLRValor
INDIndicador
TPTipo
DESCDescrição

Essas abreviações praticamente viraram um idioma próprio do mercado financeiro.


Os níveis da Data Division

Agora chegamos ao coração do COBOL.

Os famosos Levels.


Level 01

Representa um registro completo.

01 WS-CLIENTE.

Pense nele como uma pasta.

Dentro dela existirão documentos.


Level 05

Representa divisões principais.

01 WS-CLIENTE.

   05 WS-NOME.

   05 WS-CPF.

   05 WS-ENDERECO.

É o nível mais utilizado.


Level 10

Subdivisão.

05 WS-ENDERECO.

   10 WS-RUA.

   10 WS-NUMERO.

   10 WS-BAIRRO.

Level 15, 20, 25...

São apenas níveis hierárquicos.

01 CLIENTE

   05 ENDERECO

      10 CIDADE

         15 CEP

O COBOL não exige números específicos.

Apenas respeita a hierarquia.

Na prática, porém, muitos bancos adotam:

01

05

10

15

20

para manter um padrão visual.


Quando usar Level 77?

No passado era comum.

77 WS-CONTADOR PIC 9(4).

Hoje praticamente todos utilizam:

01 WS-CONTADOR PIC 9(4).

Ou agrupam dentro de áreas.

O uso do 77 tornou-se raro em novos projetos.


O poderoso Level 88

Um dos recursos mais elegantes do COBOL.

Imagine isso.

05 WS-STATUS PIC X.

88 WS-ATIVO VALUE "A".

88 WS-INATIVO VALUE "I".

Depois:

IF WS-ATIVO

Muito melhor que:

IF WS-STATUS = "A"

O código praticamente se transforma em português.

Outro exemplo.

88 WS-SIM VALUE "S".

88 WS-NAO VALUE "N".

Ou ainda:

88 WS-CONTA-CORRENTE VALUE "01".

88 WS-CONTA-POUPANCA VALUE "02".

Esse recurso é amplamente utilizado em bancos.


Agrupe informações relacionadas

Errado:

WS-NOME

WS-CPF

WS-RUA

WS-SALDO

WS-IDADE

WS-CIDADE

Correto.

01 WS-CLIENTE.

   05 WS-NOME.

   05 WS-CPF.

   05 WS-ENDERECO.

      10 WS-RUA.

      10 WS-CIDADE.

   05 WS-SALDO.

A estrutura fica muito mais intuitiva.


REDEFINES

Poucos recursos são tão poderosos.

Imagine um arquivo.

1234567890

Pode representar:

CPF

ou

Código interno

Não faz sentido duplicar memória.

Usamos:

01 WS-AREA.

   05 WS-DADOS PIC X(10).

01 WS-CPF REDEFINES WS-DADOS.

   05 WS-NUMERO PIC 9(10).

A memória é exatamente a mesma.

Apenas muda a interpretação.


Onde bancos usam REDEFINES?

Muito frequentemente em:

  • layouts CNAB

  • buffers CICS

  • mensagens MQ

  • áreas de comunicação

  • protocolos

  • APIs

  • conversões numéricas

  • interpretação de bytes


Cuidados com REDEFINES

Nunca faça isso sem entender o layout.

Porque alterar uma redefinição altera todas.

É literalmente a mesma memória.


RENAMES

Pouca gente conhece.

Exemplo.

01 WS-REGISTRO.

   05 WS-NOME.

   05 WS-ENDERECO.

   05 WS-CIDADE.

66 WS-DADOS-CADASTRAIS
RENAMES WS-NOME THRU WS-CIDADE.

Agora podemos manipular todo esse trecho como um único grupo lógico.

Hoje aparece menos que REDEFINES, mas ainda existe em sistemas legados e alguns frameworks internos.


CONSTANTES

Nunca escreva:

IF WS-TIPO = "A"

Prefira:

78 ATIVO VALUE "A".

IF WS-TIPO = ATIVO

Ou

01 WS-CONSTANTES.

   05 WS-TP-ATIVO VALUE "A".

   05 WS-TP-INATIVO VALUE "I".

O significado fica explícito.


PIC correto faz diferença

Texto.

PIC X(30)

Numérico.

PIC 9(5)

Decimal.

PIC S9(9)V99 COMP-3

Valor monetário.

PIC S9(11)V99 COMP-3

Nunca utilize texto para armazenar números quando eles serão calculados.


COMP, COMP-3 e DISPLAY

Nos bancos é comum encontrar a seguinte estratégia:

DISPLAY

para entrada e saída.

COMP

para cálculos inteiros.

COMP-3

para valores financeiros.

Exemplo.

05 WS-SALDO
PIC S9(11)V99 COMP-3.

Além de economizar espaço, melhora desempenho e precisão decimal.


Inicialização

Sempre inicialize.

VALUE ZERO.

VALUE SPACES.

VALUE LOW-VALUES.

VALUE HIGH-VALUES.

Ou utilize

INITIALIZE

Evite depender do conteúdo anterior da memória.


Um erro clássico

05 WS-NOME PIC X(30).

Depois.

MOVE "JOAO" TO WS-NOME

Comparação.

IF WS-NOME = "JOAO"

Pode funcionar.

Pode não funcionar.

Por quê?

Porque existem espaços restantes.

Muitos bancos utilizam:

FUNCTION TRIM

ou

INSPECT

para evitar problemas.


Tabelas OCCURS

Sempre nomeie corretamente.

05 WS-CLIENTES OCCURS 100 TIMES.

   10 WS-NOME.

   10 WS-SALDO.

Índices separados.

77 WS-IDX PIC S9(4) COMP.

Ou

INDEXED BY IDX-CLIENTE

Muito mais eficiente.


Evite mágicas

Nunca faça:

MOVE 1 TO WS-X.

Depois.

IF WS-X = 1

Prefira.

88 WS-PROCESSADO VALUE 1.

Muito mais legível.


Organização visual

Bancos normalmente alinham tudo.

05 WS-NOME            PIC X(40).

05 WS-CPF             PIC 9(11).

05 WS-SALDO           PIC S9(09)V99 COMP-3.

05 WS-DATA-NASC       PIC 9(08).

Pode parecer detalhe.

Mas melhora muito a leitura.


Comentários úteis

Evite.

* Nome.

Prefira.

* Dados recebidos do cadastro central.

* Área utilizada para integração com PIX.

* Buffer utilizado pelo CICS.

Explique o motivo.

Não o óbvio.


╔══════════════════════════════════════════════════════════════════════╗
║                     COBOL DATA DIVISION                             ║
║               "Tudo começa pelos dados."                            ║
╚══════════════════════════════════════════════════════════════════════╝

                       PROGRAMA COBOL
                             │
                             ▼
                  WORKING-STORAGE SECTION
                             │
        ┌────────────────────┼────────────────────┐
        │                    │                    │
        ▼                    ▼                    ▼
   WS-CONTROLE          WS-ENTRADA          WS-SAÍDA
        │                    │                    │
        ▼                    ▼                    ▼
     Variáveis           Arquivos           Resultados
     de Trabalho         Entrada            Processados



              Hierarquia dos Levels (Níveis)

01 WS-CLIENTE
│
├──05 WS-DADOS-PESSOAIS
│    ├──10 WS-NOME
│    ├──10 WS-CPF
│    └──10 WS-DATA-NASCIMENTO
│
├──05 WS-ENDERECO
│    ├──10 WS-RUA
│    ├──10 WS-NUMERO
│    ├──10 WS-CIDADE
│    └──10 WS-CEP
│
└──05 WS-DADOS-BANCARIOS
     ├──10 WS-AGENCIA
     ├──10 WS-CONTA
     └──10 WS-SALDO


             Quanto maior o nível...
                   menor o detalhe.

        01  → Registro completo
        05  → Grupo principal
        10  → Campo
        15  → Subcampo
        20+ → Especializações



                Organização Recomendada

                 +-------------------+
                 |   01 WS-CLIENTE   |
                 +-------------------+
                          │
          ┌───────────────┼───────────────┐
          ▼               ▼               ▼
     IDENTIFICAÇÃO    ENDEREÇO       FINANCEIRO
          │               │               │
          ▼               ▼               ▼
     CPF / Nome      Rua / CEP     Conta / Saldo



                Prefixos Mais Utilizados

WS-  → Working Storage
LK-  → Linkage Section
LS-  → Local Storage
DFH- → CICS
SQL- → DB2
IX-  → Índice
CT-  → Constante
FL-  → Flag
TP-  → Tipo
DT-  → Data
HR-  → Hora
NR-  → Número
CD-  → Código
VLR- → Valor
QTD- → Quantidade



            REDEFINES (Mesma memória)

          +-------------------------+
          |      WS-DADOS           |
          |        X(20)            |
          +-------------------------+
                    ▲
                    │
         REDEFINES  │
                    │
          +-------------------------+
          |       WS-CPF            |
          |        9(20)            |
          +-------------------------+

      Uma única área de memória.
      Duas interpretações diferentes.



             RENAMES (Grupo Lógico)

01 WS-REGISTRO
│
├──05 WS-NOME
├──05 WS-ENDERECO
├──05 WS-CIDADE
└──05 WS-CEP

          │
          ▼

66 WS-DADOS-CADASTRAIS
   RENAMES WS-NOME THRU WS-CEP



             Nível 88 (Legibilidade)

        +-------------------+
        | WS-STATUS    PIC X|
        +-------------------+
               │
        ┌──────┴──────┐
        ▼             ▼
88 WS-ATIVO      88 WS-INATIVO
 VALUE "A"         VALUE "I"

Ao invés de:

IF STATUS = "A"

Escrevemos:

IF WS-ATIVO



              O Fluxo de uma Variável

 Declaração
      │
      ▼
 Inicialização
      │
      ▼
 Validação
      │
      ▼
 Processamento
      │
      ▼
 Saída
      │
      ▼
 Encerramento



      O que um iniciante costuma fazer...

WS-X
WS-AUX
WS-TEMP
WS-AREA
WS-DADOS

                 😢



      O que um profissional faz...

WS-VLR-SALDO-ATUAL
WS-DT-PROCESSAMENTO
WS-QTD-CLIENTES
WS-FL-CONTA-ATIVA
WS-CD-AGENCIA

                 😎



╔════════════════════════════════════════════════════════════╗
║ "Programas envelhecem. Dados permanecem."                 ║
║                                                           ║
║ Quanto melhor a Data Division...                          ║
║ ...mais simples será todo o restante do programa.         ║
╚════════════════════════════════════════════════════════════╝ .


Os erros mais comuns dos iniciantes

  • Variáveis com nomes sem significado.

  • Misturar entrada, saída e trabalho na mesma área.

  • Não utilizar grupos.

  • Declarar tudo como PIC X.

  • Ignorar COMP-3 para valores monetários.

  • Não utilizar nível 88.

  • Criar dezenas de variáveis AUX.

  • Usar REDEFINES sem conhecer o layout.

  • Não inicializar variáveis.

  • Declarar estruturas sem padronização.

  • Copiar layouts diferentes para a mesma área.

  • Esquecer alinhamento e organização.


O estado da arte em 2024

Embora o COBOL tenha mais de seis décadas, a Data Division continua evoluindo.

Nos ambientes modernos do IBM Enterprise COBOL 6.x e z/OS 3.1, as melhores práticas incluem:

  • nomes semânticos e consistentes;

  • estruturas alinhadas a modelos de negócio;

  • uso intensivo de COPYBOOKs compartilhados para evitar duplicação;

  • integração com JSON, XML e APIs REST preservando tipos corretos;

  • preferência por COMP-3 para valores financeiros e COMP/BINARY para cálculos;

  • uso de USAGE INDEX, 88-level, INITIALIZE e funções intrínsecas;

  • validação por ferramentas de análise estática como IBM Application Delivery Foundation, SonarQube (quando integrado) e padrões internos de qualidade.

Em muitos bancos, nenhuma variável nasce por acaso. Ela segue convenções documentadas, passa por revisão técnica e, frequentemente, é reutilizada por dezenas ou centenas de programas por meio de copybooks corporativos. Isso reduz erros, facilita integrações e garante consistência entre sistemas.


Curiosidades

  • O COBOL foi criado em 1959, e sua estrutura hierárquica de dados influenciou diversas linguagens posteriores.

  • Muitos layouts bancários brasileiros (CNAB 240 e 400 posições) dependem diretamente de grupos de níveis (01, 05, 10...) para mapear registros.

  • REDEFINES foi um dos primeiros mecanismos eficientes de reutilização de memória da história das linguagens comerciais.

  • Grandes bancos possuem programas com mais de 40 anos em produção cujas declarações de variáveis permanecem praticamente inalteradas, justamente porque foram bem projetadas desde o início.


A Filosofia Bellacosa Mainframe

Imagine uma biblioteca.

Cada livro possui uma prateleira.

Cada prateleira possui uma categoria.

Cada categoria possui uma etiqueta.

Agora imagine uma biblioteca onde todos os livros estão jogados no chão.

Ambas funcionam.

Mas apenas uma continua funcionando depois de cinquenta anos.

A Data Division é essa biblioteca.

Cada variável é um livro.

Cada nível é uma prateleira.

Cada nome é uma etiqueta.

Quando você declara uma variável pensando apenas no programa de hoje, escreve código.

Quando a declara pensando no colega que fará manutenção daqui a vinte anos, constrói engenharia de software.

E é exatamente essa mentalidade que diferencia um programador COBOL de um verdadeiro profissional de mainframe.

No fim das contas, programas mudam, regras de negócio evoluem e tecnologias se renovam. Uma Data Division bem organizada, porém, continua sendo uma das maiores demonstrações de maturidade técnica que um desenvolvedor pode deixar como legado.


terça-feira, 10 de agosto de 2021

REDEFINES, Compiler Options e o Diagnóstico que o COBOL Iniciante Não Vê

 

Bellacosa Mainframe e o redefines em cobol risco de perigo eminente

☕ Um Café no Bellacosa Mainframe

REDEFINES, Compiler Options e o Diagnóstico que o COBOL Iniciante Não Vê

🩺 House M.D. entra no CPD: “O compilador não mente. O programador é que perguntou a coisa errada.”

Existe um momento inevitável na vida de todo programador COBOL.

Você está diante de um programa aparentemente simples.

O JCL compilou.

O retorno foi bonito.

MAXCC=0

Nenhuma explosão.

Nenhum abend.

Nenhum operador telefonando.

Nenhum gerente atravessando o corredor com aquela expressão típica de quem acabou de descobrir que o processamento noturno está duas horas atrasado.

Você olha para o código e pensa:

— Funcionou.

E, em algum lugar do hospital Princeton-Plainsboro do mainframe, o Dr. Gregory House manca pelo corredor, toma um Vicodin imaginário e responde:

— Não. Apenas ainda não morreu.

Bem-vindo ao Bellacosa Mainframe.

Hoje vamos investigar um daqueles problemas que parecem pequenos demais para merecer atenção até o dia em que deixam de ser pequenos:

REDEFINES com tamanhos diferentes.

E, a partir dele, vamos abrir uma porta muito maior:

  • como o COBOL organiza memória;

  • o que REDEFINES realmente faz;

  • por que o compilador pode aceitar coisas que você não deveria escrever;

  • como identificar diferenças de tamanho;

  • como usar MAP;

  • como usar XREF;

  • quais opções de compilação ajudam;

  • onde essas opções podem ser configuradas;

  • o que é CBL;

  • o que é PROCESS;

  • o que é SYSOPTF;

  • o que é OPTFILE;

  • o que é IGYCDOPT;

  • como funciona a precedência das opções;

  • e por que um bom programador COBOL precisa aprender a ler o listing como um médico lê um exame de sangue.

Pegue o café.

Temos um paciente.



🩻 Caso clínico: o REDEFINES suspeito

Imagine o seguinte código:

       WORKING-STORAGE SECTION.

       01  WS-AREA-ORIGINAL.
           05 WS-CAMPO-A        PIC X(10).
           05 WS-CAMPO-B        PIC X(10).

       01  WS-AREA-NOVA
           REDEFINES WS-AREA-ORIGINAL.
           05 WS-CAMPO-C        PIC X(30).

O iniciante olha rapidamente.

Área original:

10 + 10 = 20 bytes

Área redefinida:

30 bytes

Logo nasce a pergunta:

“Como uma área de 30 bytes pode redefinir uma área que aparentemente tem 20?”

Excelente pergunta.

E é exatamente aí que mora a armadilha.



🧠 Primeiro diagnóstico: REDEFINES não significa “nova variável”

Talvez o erro conceitual mais comum seja imaginar que isto:

01 A PIC X(10).
01 B REDEFINES A PIC X(10).

significa:

A = 10 bytes
B = 10 bytes
TOTAL = 20 bytes

Não.

Pense em uma gaveta.

Existe uma única gaveta física.

Você pode colocar uma etiqueta nela escrito:

A

ou outra etiqueta:

B

Mas continua sendo a mesma gaveta.

Conceitualmente:

             MEMÓRIA

      ┌──────────────────┐
A --> │ A B C D E F G H I J │
      └──────────────────┘
               ↑
B -------------┘

A e B são duas maneiras diferentes de interpretar os mesmos bytes.

Então grave isto:

REDEFINES cria uma nova visão lógica, não necessariamente uma nova área independente de storage.

Uma frase Bellacosa para decorar:

REDEFINES não constrói outro apartamento. Ele entrega outra planta do mesmo apartamento.



🏠 Um exemplo clássico e correto

Datas são perfeitas para entender isso.

       01  WS-DATA.
           05 WS-DATA-INTEIRA   PIC X(08).

       01  WS-DATA-DETALHE
           REDEFINES WS-DATA.
           05 WS-ANO            PIC 9(04).
           05 WS-MES            PIC 9(02).
           05 WS-DIA            PIC 9(02).

Se WS-DATA-INTEIRA contiver:

20260816

a mesma sequência pode ser visualizada assim:

WS-DATA-INTEIRA

┌─────────────────────────┐
│ 2 0 2 6 0 8 1 6         │
└─────────────────────────┘

ou:

WS-DATA-DETALHE

┌────────────┬──────┬──────┐
│ WS-ANO     │ MÊS  │ DIA  │
│ 2026       │ 08   │ 16   │
└────────────┴──────┴──────┘

Mesmos oito bytes.

Duas interpretações.

Perfeito.


🚨 Então o tamanho precisa ser sempre igual?

Aqui começa a parte interessante.

Para ensinar um iniciante, eu usaria uma regra extremamente conservadora:

TAMANHO DO REDEFINES
        =
TAMANHO DA ÁREA REDEFINIDA

Essa regra evita muitos erros.

Mas o COBOL real é mais complexo.

Dependendo do nível da estrutura, da versão do compilador, das regras da linguagem e do Enterprise COBOL utilizado, algumas redefinições com comprimentos diferentes podem ser aceitas.

Ou seja:

O compilador aceitar não significa que o design seja bom.

House provavelmente escreveria no quadro:

COMPILES ≠ CORRECT

E depois apagaria metade da palavra só para irritar a equipe.


🧪 O erro realmente perigoso

O problema não é simplesmente escrever:

05 B REDEFINES A PIC X(30).

O problema é escrever isso sem perceber as implicações.

Porque daí temos uma diferença enorme entre duas perguntas:

Pergunta errada

“O compilador aceitou?”

Pergunta certa

“O layout de memória resultante é exatamente aquele que eu acredito que seja?”

A segunda pergunta separa quem está apenas digitando COBOL de quem está começando a entender COBOL.


🔬 Não confie apenas nos olhos: use o MAP

Aqui aparece um dos recursos mais úteis e menos apreciados pelos iniciantes:

MAP

Ao compilar com MAP, o Enterprise COBOL produz informações sobre o layout da DATA DIVISION.

Em outras palavras:

o compilador mostra como ele entendeu seus campos.

Isso é quase um raio-X da memória.

Imagine:

       01 WS-REGISTRO.
          05 WS-NOME     PIC X(20).
          05 WS-IDADE    PIC 99.
          05 WS-SALARIO  PIC S9(7)V99 COMP-3.

Você pode acreditar que sabe exatamente como isso está organizado.

Mas o listing é a resposta do compilador.

E sempre que houver estruturas complexas com:

REDEFINES
OCCURS
COMP
COMP-3
SYNC
SIGN
GROUP ITEMS
COPYBOOKS

a leitura do mapa se torna extremamente valiosa.


🩻 MAP é o raio-X; SOURCE é a ficha clínica

Eu normalmente colocaria em desenvolvimento algo semelhante a:

MAP
SOURCE
XREF(FULL)

Cada opção responde uma pergunta diferente.

SOURCE

Você vê o fonte associado ao listing.

Isso facilita conectar mensagens, offsets e referências ao código que realmente foi compilado.

Parece trivial.

Até você descobrir que o programa que estava olhando não era exatamente o programa que entrou na compilação.

Copybooks entram.

Pré-compiladores entram.

Conditional compilation entra.

E de repente:

“Mas no meu fonte não está assim!”

Bem-vindo ao mainframe.

O compilador não lê suas intenções.

Ele lê aquilo que efetivamente recebeu.


🧬 XREF(FULL): quem mexeu no paciente?

XREF significa referência cruzada.

Imagine que você encontra:

WS-CUSTOMER-AREA

e quer saber:

  • onde foi declarada;

  • onde foi usada;

  • quem altera;

  • quem consulta;

  • quais parágrafos fazem referência a ela.

É aí que:

XREF(FULL)

se torna extremamente útil.

Ele não é especificamente um detector mágico de REDEFINES incorreto.

Mas responde uma pergunta fundamental na investigação:

“Quem está usando esta área?”

House chamaria isso de procurar quem teve contato com o paciente antes dos sintomas aparecerem.


🧯 Regra prática para o iniciante

Sempre que você encontrar:

REDEFINES

pare.

Faça quatro perguntas:

1. Qual é o tamanho da área original?

2. Qual é o tamanho da redefinição?

3. Essa diferença é intencional?

4. Eu conferi o MAP?

Essa pausa de trinta segundos pode economizar horas de debugging.


🧮 Não confie demais na contagem visual

Isto parece fácil:

05 CAMPO-A PIC X(10).
05 CAMPO-B PIC X(10).

Total:

20

Mas layouts reais podem envolver:

05 VALOR-A PIC S9(9) COMP.
05 VALOR-B PIC S9(7)V99 COMP-3.
05 TABELA OCCURS 15 TIMES.

Agora contar “na cabeça” começa a ficar menos divertido.

E podemos adicionar:

SYNC
USAGE
SIGN
OCCURS DEPENDING ON
nested groups
copybooks

Pronto.

Você não está mais contando caracteres.

Está fazendo arqueologia.


🗿 Easter egg número 1: Indiana Jones e o Copybook Perdido

Todo programador COBOL experiente já encontrou algo assim:

COPY ABCD001.

Você abre.

Dentro existe:

COPY ABCD002.

Abre o segundo.

Existe:

COPY ABCD003.

Quinze minutos depois você está procurando um copybook criado em 1989 por um programador chamado Geraldo que se aposentou antes do Windows 95.

Indiana Jones tinha menos trabalho.


🧪 Existe warning para REDEFINES?

A resposta precisa ser cuidadosamente entendida.

O Enterprise COBOL possui diversas opções de diagnóstico e comportamento, incluindo regras relacionadas a construções da linguagem.

Uma opção interessante é a família:

RULES

e, dentro dela, configurações relacionadas à permissividade de redefinições.

Por exemplo:

RULES(NOLAXREDEF)

pode tornar determinadas situações de REDEFINES mais rigorosas.

Mas atenção:

não pense em NOLAXREDEF como um “detector universal de REDEFINES maior”.

Isso seria simplificar demais.

Ele atua sobre regras específicas da linguagem e situações de redefinição que o compilador poderia tratar de maneira mais permissiva.

Então a estratégia profissional não deve ser:

“Coloquei NOLAXREDEF, estou protegido.”

Deve ser:

compiler diagnostics
+
MAP
+
coding standard
+
static analysis
+
code review

Defesa em profundidade.

Segurança da informação descobriu isso faz décadas.

COBOL também merece.


🏥 Diagnóstico diferencial

House raramente acreditava na primeira hipótese.

Você também não deveria.

Se um programa possui corrupção de campos, valores estranhos ou informações que aparecem “do nada”, REDEFINES é apenas uma das hipóteses.

Também investigue:

MOVE com tamanhos incompatíveis
subscripts incorretos
índices fora do limite
OCCURS
OCCURS DEPENDING ON
reference modification
COMP-3 inválido
campos numéricos contendo lixo
copybook incompatível
arquivo com LRECL errado
layout diferente entre produtor e consumidor
LINKAGE SECTION incorreta
CALL com assinatura incompatível
CICS COMMAREA
MQ payload
VSAM
Db2 host variables

O sintoma pode aparecer em um campo.

A doença pode estar cinquenta linhas antes.

Ou cinquenta programas antes.


🧰 Minha configuração de investigação

Para ambiente de desenvolvimento, algo nessa filosofia é ótimo:

SOURCE
MAP
XREF(FULL)

e opções adicionais de diagnóstico conforme a política da instalação.

Não estou dizendo:

“Use exatamente esse conjunto em qualquer empresa.”

Cada shop possui padrões, versões, custos de listing, ferramentas, pipelines e políticas.

Mas o princípio é sólido:

Durante desenvolvimento, peça ao compilador para mostrar o máximo possível sobre o que ele entendeu.


🔧 “Mas onde coloco esses parâmetros?”

Agora chegamos a outra pergunta fundamental.

Muitos iniciantes acreditam que as opções de compilação existem apenas no JCL:

//COBOL EXEC PGM=IGYCRCTL,
// PARM='MAP,XREF,SOURCE'

Não.

O JCL é apenas uma das portas.

E entender isso muda completamente sua visão sobre compilação COBOL.


🚪 Porta 1 — PARM no JCL

A forma mais conhecida:

//COB EXEC PGM=IGYCRCTL,
// PARM='MAP,XREF(FULL),SOURCE'

Ou por meio de uma PROC corporativa.

É simples.

É visível.

E funciona bem.

Mas existe uma fraqueza:

depende do ambiente de compilação utilizado.

Se alguém usar outra PROC, outro pipeline ou outro processo, aquelas opções podem mudar.


🚪 Porta 2 — CBL

Você pode colocar opções diretamente no fonte.

Exemplo:

       CBL MAP,XREF(FULL),SOURCE
       IDENTIFICATION DIVISION.
       PROGRAM-ID. PACIENTE.

Isso significa:

“Este programa solicita essas opções.”

É muito poderoso porque a configuração viaja junto com o fonte.


🚪 Porta 3 — PROCESS

Outra sintaxe:

       PROCESS MAP,XREF(FULL),SOURCE
       IDENTIFICATION DIVISION.

Conceitualmente, PROCESS e CBL servem para informar opções ao compilador a partir do próprio programa.

Existe uma regra importante:

essas diretivas aparecem no início apropriado do fonte.

Elas não são statements executáveis.

Você não coloca:

PROCEDURE DIVISION.
    PROCESS MAP.

Isso seria como tentar mudar a configuração do aparelho de raio-X depois que o paciente já voltou para casa.


🧳 Quando usar CBL ou PROCESS?

Imagine uma aplicação que, por característica própria, precisa sempre ser compilada com determinada configuração.

Nesse caso faz sentido considerar:

CBL / PROCESS

Mas existe uma discussão arquitetural importante.

Você quer que:

cada programa decida suas próprias opções

ou:

a empresa defina um padrão central?

Essa decisão importa.

Porque programas vivem décadas.

Padrões corporativos mudam.

Compiladores mudam.

Ambientes mudam.


🚪 Porta 4 — SYSOPTF e OPTFILE

Agora entramos numa solução muito interessante para shops organizadas.

Em vez de escrever quarenta opções no JCL, você pode manter um arquivo de opções.

Algo conceitualmente assim:

EMPRESA.COBOL.OPTIONS(DEV)

contendo:

MAP
SOURCE
XREF(FULL)

E associá-lo como:

//SYSOPTF DD DSN=EMPRESA.COBOL.OPTIONS(DEV),DISP=SHR

O compilador pode então consumir essas opções através do mecanismo apropriado de option file.

Isso permite criar perfis.

Por exemplo:

EMPRESA.COBOL.OPTIONS(DEV)

EMPRESA.COBOL.OPTIONS(TEST)

EMPRESA.COBOL.OPTIONS(PROD)

EMPRESA.COBOL.OPTIONS(DEBUG)

EMPRESA.COBOL.OPTIONS(MIGRATION)

Isso é muito mais elegante do que copiar e colar parâmetros em dezenas de PROCs.


🧠 Easter egg número 2: House odeia copy & paste

Se House fosse tech lead COBOL, provavelmente diria:

— Você copiou quarenta opções de compilação de um JCL de 2017 sem saber o que fazem?

— Sim.

— Então não temos um bug. Temos uma religião.


🚪 Porta 5 — IGYCDOPT

Agora chegamos ao porão do hospital.

Lugar onde iniciantes raramente entram.

O Enterprise COBOL possui defaults de instalação.

Um dos nomes importantes nesse universo é:

IGYCDOPT

É nele que a organização pode estabelecer defaults para o compilador.

Pense assim:

programador
   |
   v
programa COBOL
   |
   v
PROC/JCL
   |
   v
Enterprise COBOL
   |
   v
defaults da instalação

O IGYCDOPT permite que a instalação diga:

“Se ninguém especificar nada diferente, use isto.”

E certas opções podem ainda ser controladas de modo que não sejam livremente sobrescritas.

É aí que recomendação vira governança.


🏛️ Política versus preferência

Existe uma diferença gigante entre:

“Recomendamos usar esta opção.”

e:

“A instalação está configurada desta maneira.”

Na primeira:

João usa.

Maria esquece.

Pedro usa outra PROC.

Carlos compila no pipeline antigo.

Na segunda:

a infraestrutura ajuda a garantir consistência.

Esse princípio aparece em tudo:

RACF
DevSecOps
Git
pipeline
quality gates
compiler defaults

Se algo é realmente importante, tente automatizar.


🧭 Mas quem ganha quando existem várias opções?

Excelente pergunta.

Imagine:

instalação:

NOMAP

JCL:

MAP

fonte:

CBL NOMAP

Qual vale?

Isso nos leva à:

⚔️ PRECEDÊNCIA DAS OPÇÕES

Você precisa entender que opções podem ser fornecidas por diferentes origens.

Conceitualmente:

INSTALLATION DEFAULTS
        ↓
INVOCATION / JCL
        ↓
PROCESS / CBL

mas existem particularidades, exceções e opções que podem ser fixadas pela instalação.

Então nunca faça debugging baseado apenas em:

“Eu tenho certeza de que a PROC usa MAP.”

Abra o listing.

Veja:

OPTIONS IN EFFECT

O compilador costuma informar quais opções efetivamente estavam ativas.

Essa seção vale ouro.


🔍 Regra Bellacosa número 1

Não pergunte qual opção estava no JCL. Pergunte qual opção estava em efeito.

Existe uma diferença brutal.

O JCL representa intenção.

O listing representa execução.


🧾 Leia o listing!

Aqui está talvez a maior dica deste artigo.

Programador iniciante pensa que o listing serve para:

achar erro de compilação

Programador intermediário usa para:

achar warning

Programador experiente usa o listing como:

documentação do programa compilado

Ele procura:

compiler version
compiler options
messages
data map
cross reference
code generation
statistics
source expansion

Você começa olhando um erro.

Termina entendendo como o compilador enxerga seu programa.


🩸 MAXCC=0 é apenas pressão arterial normal

Este merece moldura.

Você recebeu:

MAXCC=0

Parabéns.

Isso significa apenas que aquele job terminou com aquela condição.

Não significa:

lógica correta
layout correto
regra de negócio correta
performance boa
thread safety
dados corretos
segurança correta
arquivo correto
transação correta

House olha o monitor cardíaco.

Paciente vivo.

Ele não diz:

— Curado.

Ele pergunta:

— Por que ele desmaiou?

Faça o mesmo.


🔬 Passo a passo para investigar um REDEFINES

Encontrou:

REDEFINES

Faça isto.

Passo 1 — identifique a área original

Exemplo:

01 WS-ORIGINAL.
   05 A PIC X(10).
   05 B PIC X(10).

Calcule:

20 bytes

Passo 2 — identifique todas as redefinições

Pode existir mais de uma:

01 WS-TEXTO REDEFINES WS-ORIGINAL.
...

01 WS-NUMERICO REDEFINES WS-ORIGINAL.
...

01 WS-FLAGS REDEFINES WS-ORIGINAL.
...

Não pare na primeira.


Passo 3 — calcule os comprimentos

Faça isso cuidadosamente.

Principalmente se houver:

COMP
COMP-3
OCCURS
nested groups

Passo 4 — procure a intenção

Pergunte:

“Por que alguém criou este REDEFINES?”

Talvez seja:

header/body
mensagem de vários tipos
record type
layout de arquivo
estrutura histórica
flags
data
packed decimal
interface externa

Nem todo código estranho está errado.

Às vezes existe uma razão escrita em 1994.

Às vezes não.


🗿 Easter egg número 3: comentário de 1994

Você encontra:

*> NÃO ALTERAR ESTA ÁREA

Sem explicação.

Sem nome.

Sem ticket.

Sem documentação.

Naturalmente você pensa:

— Por quê?

A resposta está enterrada em uma fita magnética enviada para Iron Mountain durante o governo Itamar Franco.

Não altere.


🧪 Passo 5 — compile com MAP

Veja offsets.

Veja comprimentos.

Veja como o compilador efetivamente montou a área.

Nunca deixe a teoria vencer o mapa real.


🔍 Passo 6 — consulte o XREF

Descubra quem usa:

área original
área redefinida
campos individuais

Isso ajuda muito a entender o impacto.


🧬 Passo 7 — procure interfaces

Essa área vai para algum lugar?

WRITE
CALL
EXEC CICS LINK
EXEC CICS XCTL
EXEC CICS SEND
EXEC CICS RECEIVE
MQPUT
MQGET

Ou talvez:

arquivo VSAM
arquivo sequencial
Db2
IMS
socket
API
z/OS Connect

A área interna pode ter trinta bytes.

A interface externa pode esperar vinte.

Agora temos um problema de verdade.


💣 O pior cenário: contratos de dados

Imagine:

Programa A produz:

20 bytes

Programa B acredita que recebe:

30 bytes

Programa C possui um copybook antigo com:

24 bytes

Todos compilam.

Todos possuem:

MAXCC=0

House sorri.

— Finalmente um caso interessante.

Isso é exatamente o tipo de problema que aparece em ambientes legados.

O bug não está em um programa.

Está no contrato invisível entre programas.


🧠 Por isso copybook é tão importante

Copybooks não são apenas uma conveniência para evitar repetição.

Eles funcionam como contratos compartilhados de dados.

Quando bem utilizados:

Programa A ─┐
Programa B ─┼── COPY CUSTOMER
Programa C ─┘

todos enxergam a mesma definição.

Mas existe outro perigo:

versões diferentes do mesmo copybook

Programa A compilado ontem.

Programa B compilado seis anos atrás.

O dataset do copybook foi atualizado.

O módulo load de B continua com o layout antigo.

Agora você possui duas verdades.

Uma no fonte.

Outra no executável.

Bem-vindo novamente ao mainframe.


🔦 Static analysis: não espere um humano perceber

Aqui está uma excelente regra automática:

FOR EACH REDEFINES

compare
LENGTH(original)
with
LENGTH(redefinition)

Se:

=

normal.

Se:

<>

alerta.

Se:

redefinition > original

alerta forte.

Não porque todo caso seja necessariamente inválido.

Mas porque todo caso merece explicação.

Esse é o princípio de uma boa ferramenta estática:

destacar o que é incomum o bastante para merecer revisão humana.


🤖 Code review aumentado por IA

Aqui está uma aplicação interessante para IA em mainframe.

Imagine um pipeline lendo COBOL e produzindo:

WARNING COBOL-RD-001

WS-TRANSACTION-V2
redefines
WS-TRANSACTION

Original logical length: 128
Redefinition length: 136

Difference: +8 bytes

Review recommended.

Depois correlaciona com:

CALL USING
CICS COMMAREA
COPYBOOK
MQ
arquivo

Agora estamos usando IA não para substituir o programador.

Estamos usando IA para apontar:

“Ei, House. Esse exame aqui está estranho.”


🧯 Regra Bellacosa número 2

Nunca trate warning como decoração.

Compile listings antigos e você encontrará:

W
W
W
W
W
W
W

O programa está em produção há quinze anos.

Todo mundo diz:

— Sempre funcionou.

Essa é possivelmente uma das frases mais perigosas da informática.


🐸 “Sempre funcionou”

Uma aplicação COBOL antiga pode ter sobrevivido:

mudanças de hardware
mudanças de compilador
mudanças de sistema operacional
mudanças de middleware
novas versões de Db2
novas versões de CICS
mudanças de encoding
migrações
novos copybooks

Até que alguém recompila.

Então aparece:

“Funcionava antes.”

Talvez.

Talvez apenas estivesse dependendo de um comportamento antigo.


🧬 Compiler migration é medicina geriátrica

Migrar COBOL 4 para COBOL 6, por exemplo, não é simplesmente:

recompile

Você está trazendo código escrito sob determinadas hipóteses para outro ambiente.

Coisas que passaram despercebidas por décadas podem emergir.

Por isso opções de diagnóstico, listings, testes e análise estática são tão importantes.


🔐 Onde eu colocaria as opções?

Aqui entra arquitetura de engenharia.

Para um programa específico

Considere:

CBL
PROCESS

quando fizer sentido que aquela configuração acompanhe o fonte.


Para um projeto

Pode fazer sentido:

SYSOPTF
option file

Para toda a empresa

Pode fazer sentido usar:

defaults de instalação
IGYCDOPT

Para uma execução específica

Use:

PARM no JCL

Isso cria quatro níveis mentais:

PROGRAMA
PROJETO
PIPELINE
EMPRESA

Uma arquitetura muito melhor do que:

“coloca esse PARM aí e vê se funciona.”

🏗️ Um padrão de shop possível

Imagine:

           CORPORATIVO
              |
          IGYCDOPT
              |
     -------------------
     |                 |
  projeto A         projeto B
     |                 |
 SYSOPTF           SYSOPTF
     |                 |
   PROC              PROC
     |                 |
 programa           programa
 CBL/PROCESS        CBL/PROCESS

Agora você consegue controlar:

defaults
exceções
projetos
programas especiais

Isso é engenharia.


🚨 Não transforme opção de compilador em superstição

Outro erro comum:

“Fulano disse para usar SSRANGE.”

Então alguém coloca:

SSRANGE

sem saber o que ela faz.

Depois alguém copia.

Depois vira padrão.

Dez anos depois ninguém sabe por quê.

Toda opção de compilador deveria possuir pelo menos:

nome
objetivo
impacto
ambiente
quando usar
quando não usar

📚 Crie um catálogo corporativo

Algo simples:

OPTION: MAP

Uso:
Development / Migration

Objetivo:
Mostrar layout da Data Division.

Obrigatória:
DEV = SIM
PROD = opcional

Responsável:
Mainframe Engineering

Faça isso para:

MAP
XREF
SOURCE
SSRANGE
NUMCHECK
OPTIMIZE
ARCH
TEST
LIST
OFFSET

Seu eu do futuro agradecerá.


🧠 Easter egg número 4: Differential Diagnosis

Quando House recebe um paciente, a equipe lista hipóteses no quadro.

Faça exatamente isso no debugging.

Sintoma:

WS-VALOR contém lixo

Quadro:

REDEFINES?
MOVE?
SUBSCRIPT?
COMP-3?
COPYBOOK?
CALL?
FILE LAYOUT?
CICS?
STORAGE OVERWRITE?

Depois elimine hipóteses com evidência.

Isso é debugging profissional.

Não:

“Vou mudar isso aqui e rodar.”

🧪 O compilador é testemunha, não advogado

Ele lhe diz:

o que conseguiu compilar

Ele não garante:

o que você quis escrever

Essa distinção é central.

Um compilador pode aceitar código perfeitamente legal que implemente uma ideia completamente errada.

Exemplo:

MOVE WS-SALDO TO WS-CPF.

Talvez os campos sejam compatíveis.

O compilador não conhece sua regra de negócio.

Ele não sabe que você acabou de colocar saldo bancário dentro do CPF.

Ele apenas executa ordens.


🎯 Checklist Bellacosa para REDEFINES

Antes de aprovar qualquer REDEFINES, responda:

  • Sei exatamente qual área está sendo redefinida.

  • Conheço o tamanho da área original.

  • Conheço o tamanho de cada redefinição.

  • Entendo por que a redefinição existe.

  • Conferi COMP, COMP-3 e outros USAGE.

  • Verifiquei OCCURS.

  • Consultei o MAP.

  • Consultei referências com XREF.

  • Verifiquei copybooks relacionados.

  • Verifiquei interfaces externas.

  • Sei qual versão do compilador foi utilizada.

  • Conferi as opções efetivamente em uso.

  • Não estou confiando apenas em MAXCC=0.

Se você respondeu “não” a cinco itens:

House acabou de pedir uma ressonância.


🩺 Uma pequena autópsia de exemplo

Considere:

       01 CUSTOMER-RECORD.
          05 CUSTOMER-ID       PIC X(10).
          05 CUSTOMER-NAME     PIC X(30).

       01 CUSTOMER-ALT
          REDEFINES CUSTOMER-RECORD.
          05 CUSTOMER-DATA     PIC X(48).

O programador vê:

CUSTOMER-RECORD = 40

CUSTOMER-ALT = 48

Primeira pergunta:

Por quê?

Talvez exista uma razão.

Talvez CUSTOMER-ALT represente uma versão futura.

Talvez alguém aumentou um campo.

Talvez um copybook tenha sido alterado pela metade.

Talvez seja simplesmente erro.

O ponto é:

a diferença precisa ser explicada.


🧬 Agora imagine produção

Esse registro é enviado:

CALL 'CUSTSRV'
    USING CUSTOMER-RECORD

O programa chamado possui:

LINKAGE SECTION.

01 LK-CUSTOMER PIC X(40).

Mas o chamador manipula uma visão de 48.

Você acabou de transformar uma curiosidade de DATA DIVISION em uma investigação de interface.

Por isso mainframe não é apenas sintaxe COBOL.

É ecossistema.


🚂 O programa nunca viaja sozinho

Todo COBOL real está conectado a alguma coisa:

JCL
PROCs
Db2
CICS
IMS
VSAM
MQ
sort
files
copybooks
subprograms
APIs
RACF
z/OS

Então todo problema de layout deve ser investigado no contexto do sistema.

Esse é um dos saltos mentais mais importantes para quem começa.

Você deixa de perguntar:

“Este programa está certo?”

e começa a perguntar:

“Este programa está correto dentro dos contratos do sistema?”

Isso é maturidade.


🎬 Easter egg final: “Everybody lies”

House possui uma frase famosa:

Everybody lies.

No mainframe eu adaptaria:

Everybody assumes.

O programador assume que o campo possui 20 bytes.

O analista assume que o copybook é o mesmo.

O operador assume que MAXCC=0 significa sucesso funcional.

O arquiteto assume que a PROC é padrão.

O desenvolvedor assume que MAP estava ativo.

O time assume que aquele load module foi recompilado.

E o mainframe?

O mainframe não assume nada.

Ele executa exatamente aquilo que foi definido.


☕ Conclusão — Aprenda a investigar, não apenas a compilar

REDEFINES parece um pequeno detalhe da DATA DIVISION.

Mas ele ensina uma lição gigantesca sobre COBOL.

Ensina que existe diferença entre:

fonte

e:

layout efetivo

Entre:

intenção

e:

compilação

Entre:

programa compilado

e:

programa correto

Por isso, quando você encontrar um REDEFINES, não trate como uma palavra reservada qualquer.

Olhe o tamanho.

Olhe o mapa.

Olhe o listing.

Olhe o XREF.

Descubra quais opções de compilação estavam realmente ativas.

Saiba se vieram:

do JCL
do CBL
do PROCESS
do SYSOPTF
do option file
dos defaults da instalação

Entenda a precedência.

Conheça seu compilador.

E, principalmente, abandone uma das frases mais perigosas da profissão:

“O compilador aceitou.”

O compilador aceitar é apenas o começo da investigação.

A pergunta final continua sendo:

“O programa está fazendo exatamente aquilo que nós pensamos que ele está fazendo?”

House fecharia o prontuário.

O batch terminaria.

O café estaria frio.

E no SDSF apareceria:

MAXCC=0

Você sorriria.

Mas agora saberia que esse zero não é diagnóstico.

É apenas um sinal vital.

E programador COBOL bom não trata sinal vital.

Trata o sistema inteiro.

☕🦖

Bellacosa Mainframe — onde até um PIC X(20) pode esconder uma investigação médica, três copybooks esquecidos, duas PROCs corporativas e um comentário escrito antes de Java existir.

https://eljefemidnightlunch.blogspot.com/2022/07/alerta-vermelho-na-enterprise.html

https://eljefemidnightlunch.blogspot.com/2022/05/da-compilacao-execucao-de-um-programa.html

sexta-feira, 22 de novembro de 2019

Data Division : Quando um Programador Descobre que Cada Byte Deixa uma Impressão Digital — e que a Cena do Crime Começa Antes da PROCEDURE DIVISION

 

Bellacosa Mainframe apresenta a Data Division no COBOL

☕ Um Café no Bellacosa Mainframe

Data Division sem Mistérios para Programadores COBOL

Quando um Programador Descobre que Cada Byte Deixa uma Impressão Digital — e que a Cena do Crime Começa Antes da PROCEDURE DIVISION

Nova York, 02h17 da manhã.

A chuva escorre pelas paredes de vidro do laboratório forense enquanto os reflexos azuis das viaturas atravessam a sala. Sobre uma bancada de aço inoxidável existe algo aparentemente simples: um programa COBOL encontrado em produção depois de um processamento noturno terminar com dados inconsistentes.

Nenhum cadáver.

Nenhuma arma.

Nenhuma testemunha disposta a falar.

Apenas milhões de bytes, um arquivo sequencial, algumas áreas de memória e um saldo bancário que apareceu negativo onde jamais deveria existir um valor menor que zero.

O programador iniciante olha para o código e afirma:

— O problema deve estar na PROCEDURE DIVISION.

O investigador veterano do mainframe coloca as luvas, aproxima-se do terminal 3270 e responde:

— Esse é o primeiro erro de quem ainda não aprendeu a investigar sistemas legados. A lógica pode executar o crime, mas é na DATA DIVISION que encontramos as impressões digitais.

Bem-vindo ao laboratório forense do Bellacosa Mainframe.

Hoje não examinaremos sangue, fibras, pólvora ou DNA. Examinaremos registros, campos, buffers, parâmetros, tabelas, condições, formatos numéricos e áreas de armazenamento.

Porque, em COBOL, nenhum byte desaparece sem deixar vestígios.


Bellacosa Mainframe em DATA DIVISION em destaque

A cena do crime: o que é a DATA DIVISION?

Um programa COBOL tradicional costuma ser organizado em grandes divisões:

       IDENTIFICATION DIVISION.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       PROCEDURE DIVISION.

A IDENTIFICATION DIVISION identifica o programa.

A ENVIRONMENT DIVISION descreve aspectos do ambiente onde ele será executado.

A DATA DIVISION define os dados utilizados pelo programa.

A PROCEDURE DIVISION contém as instruções que manipulam esses dados.

Uma comparação simples seria:

DivisãoFunção
IDENTIFICATION DIVISIONIdentificação do caso
ENVIRONMENT DIVISIONDescrição da cena
DATA DIVISIONCatálogo de evidências
PROCEDURE DIVISIONReconstrução dos acontecimentos

Muitos iniciantes resumem a Data Division como “o lugar onde declaramos variáveis”.

Isso está correto, mas é incompleto.

A Data Division não apenas declara variáveis. Ela especifica:

  • o tamanho de cada campo;

  • o formato dos dados;

  • a representação física em memória;

  • a hierarquia entre campos;

  • o tempo de vida das informações;

  • a origem dos dados;

  • a forma de compartilhamento entre programas;

  • a organização de registros em arquivos;

  • as áreas utilizadas como entrada e saída;

  • as diferentes interpretações possíveis para os mesmos bytes.

É quase como se cada campo viesse acompanhado de uma ficha criminal completa.

       05 WS-SALDO PIC S9(7)V99 COMP-3.

Esta linha não diz apenas que existe um saldo.

Ela revela que:

  • o campo é numérico;

  • aceita sinal;

  • possui sete posições inteiras;

  • possui duas posições decimais implícitas;

  • utiliza formato decimal compactado;

  • ocupa uma quantidade específica de bytes;

  • precisa ser manipulado respeitando sua representação interna.

O compilador utiliza essa descrição para gerar as instruções adequadas.

Portanto, a Data Division é um contrato de memória.


O laboratório possui diferentes salas

A Data Division pode conter várias seções:

       DATA DIVISION.

       FILE SECTION.

       WORKING-STORAGE SECTION.

       LOCAL-STORAGE SECTION.

       LINKAGE SECTION.

       SCREEN SECTION.

       REPORT SECTION.

Nem todas precisam aparecer no mesmo programa.

Em sistemas corporativos atuais, as mais frequentes são:

  • FILE SECTION;

  • WORKING-STORAGE SECTION;

  • LINKAGE SECTION.

A LOCAL-STORAGE SECTION também é muito importante em programas reutilizáveis e reentrantes.

SCREEN SECTION e REPORT SECTION são mais específicas e hoje aparecem com menor frequência em ambientes IBM z/OS tradicionais.

Vamos entrar em cada sala do laboratório.


FILE SECTION: o depósito de evidências externas

A FILE SECTION descreve os registros dos arquivos utilizados pelo programa.

Um detalhe crucial: ela não armazena o arquivo inteiro na memória.

Ela normalmente representa uma área onde um registro é disponibilizado a cada operação de leitura ou gravação.

Considere o seguinte arquivo de clientes:

00001JOAO DA SILVA                 00000150000
00002MARIA OLIVEIRA                00000275050
00003PEDRO SANTOS                  00000098075

Um arquivo pode possuir milhões de registros. O programa não precisa carregar todos de uma vez.

Na FILE SECTION, descrevemos o formato de um registro:

       FILE SECTION.

       FD  ARQ-CLIENTES.

       01  REG-CLIENTE.
           05 REG-CODIGO       PIC 9(5).
           05 REG-NOME         PIC X(30).
           05 REG-SALDO        PIC 9(9)V99.

O FD significa File Description.

Ele introduz a descrição lógica do arquivo.

       FD ARQ-CLIENTES.

Logo abaixo aparece o registro:

       01 REG-CLIENTE.

Quando o programa executa:

       READ ARQ-CLIENTES

o próximo registro disponível é colocado na área associada ao arquivo.

Em termos simplificados:

Arquivo em disco
      |
      v
Sistema de arquivos
      |
      v
Buffer de entrada
      |
      v
REG-CLIENTE

Depois, o programa pode examinar os campos:

       DISPLAY REG-CODIGO
       DISPLAY REG-NOME
       DISPLAY REG-SALDO

Uma correção importante sobre a imagem

Na imagem apresentada, a File Section aparece relacionada a “variáveis temporárias”. Isso pode causar confusão.

A FILE SECTION não é normalmente utilizada como área genérica de variáveis temporárias. Sua função principal é descrever registros associados a arquivos.

As variáveis temporárias ficam geralmente na WORKING-STORAGE SECTION ou na LOCAL-STORAGE SECTION.

Em uma investigação técnica, essa distinção é importante. Colocar a etiqueta errada em uma evidência pode comprometer todo o caso.


O arquivo não existe sozinho: SELECT e FD

Em muitos programas, a declaração do arquivo possui duas partes.

Na ENVIRONMENT DIVISION, encontramos o SELECT:

       ENVIRONMENT DIVISION.

       INPUT-OUTPUT SECTION.

       FILE-CONTROL.

           SELECT ARQ-CLIENTES
               ASSIGN TO CLIENTES
               ORGANIZATION IS SEQUENTIAL
               FILE STATUS IS WS-FILE-STATUS.

Na DATA DIVISION, encontramos o FD:

       FILE SECTION.

       FD  ARQ-CLIENTES.

       01  REG-CLIENTE.
           05 REG-CODIGO       PIC 9(5).
           05 REG-NOME         PIC X(30).
           05 REG-SALDO        PIC 9(9)V99.

O SELECT descreve a relação lógica com o ambiente.

O FD descreve o registro.

É como se o SELECT informasse onde a evidência foi encontrada, enquanto o FD explicasse sua estrutura física.


FILE STATUS: o laudo que muitos esquecem de consultar

Um programa robusto não deve assumir que toda operação de arquivo funcionará corretamente.

Por isso utilizamos:

       FILE STATUS IS WS-FILE-STATUS

E declaramos:

       01 WS-FILE-STATUS       PIC XX.

Após um OPEN, READ, WRITE, REWRITE, DELETE ou CLOSE, o campo pode indicar o resultado da operação.

Exemplo:

       READ ARQ-CLIENTES
           AT END
               SET FIM-ARQUIVO TO TRUE
       END-READ

Ou:

       IF WS-FILE-STATUS NOT = '00'
           DISPLAY 'ERRO DE ARQUIVO: ' WS-FILE-STATUS
       END-IF

O valor 00 normalmente representa sucesso.

Mas atenção: os significados exatos podem variar conforme a operação e a organização do arquivo.

Uma boa prática é nunca tratar o status de arquivo como um detalhe decorativo.

Um READ malsucedido não é silêncio. É uma testemunha tentando falar.


WORKING-STORAGE SECTION: a sala central do laboratório

A WORKING-STORAGE SECTION é uma das áreas mais utilizadas em programas COBOL.

Ela contém dados que geralmente existem durante toda a execução da unidade de programa.

       WORKING-STORAGE SECTION.

       01 WS-CONTADOR          PIC 9(5) VALUE ZERO.
       01 WS-TOTAL             PIC S9(9)V99 COMP-3 VALUE ZERO.
       01 WS-FIM-ARQUIVO       PIC X VALUE 'N'.

Enquanto o programa estiver ativo, essas áreas permanecem disponíveis.

Podemos utilizar a Working-Storage para:

  • contadores;

  • acumuladores;

  • flags;

  • mensagens;

  • campos auxiliares;

  • datas;

  • áreas de entrada e saída;

  • tabelas;

  • constantes;

  • códigos de retorno;

  • estruturas temporárias;

  • copybooks;

  • campos utilizados em cálculos.

Contador

       01 WS-QTD-CLIENTES      PIC 9(7) VALUE ZERO.

Uso:

       ADD 1 TO WS-QTD-CLIENTES

Acumulador

       01 WS-TOTAL-SALDOS      PIC S9(11)V99 COMP-3
                               VALUE ZERO.

Uso:

       ADD REG-SALDO TO WS-TOTAL-SALDOS

Flag

       01 WS-FIM-ARQUIVO       PIC X VALUE 'N'.

Uso:

       IF WS-FIM-ARQUIVO = 'S'
           DISPLAY 'PROCESSAMENTO ENCERRADO'
       END-IF

Funciona, mas pode ser melhorado com nível 88.


Nível 88: o testemunho semântico

O nível 88 não reserva uma nova área de memória.

Ele fornece nomes significativos para valores ou condições de outro campo.

       01 WS-FIM-ARQUIVO       PIC X VALUE 'N'.
           88 FIM-ARQUIVO      VALUE 'S'.
           88 NAO-FIM-ARQUIVO  VALUE 'N'.

Agora podemos escrever:

       SET FIM-ARQUIVO TO TRUE

E testar:

       PERFORM UNTIL FIM-ARQUIVO

Isso é muito mais expressivo do que:

       PERFORM UNTIL WS-FIM-ARQUIVO = 'S'

Os dois funcionam, mas o nível 88 aproxima o código da linguagem do negócio.

Outro exemplo:

       01 WS-TIPO-CLIENTE      PIC X.
           88 CLIENTE-COMUM    VALUE 'C'.
           88 CLIENTE-VIP      VALUE 'V'.
           88 CLIENTE-BLOQUEADO VALUE 'B'.

Uso:

       IF CLIENTE-BLOQUEADO
           DISPLAY 'OPERACAO NAO AUTORIZADA'
       END-IF

O nível 88 é como uma legenda pericial: ele transforma valores brutos em significados compreensíveis.


VALUE: o estado inicial da evidência

A cláusula VALUE define um conteúdo inicial.

       01 WS-CONTADOR          PIC 9(5) VALUE ZERO.
       01 WS-MENSAGEM          PIC X(30)
                               VALUE 'INICIO DO PROCESSAMENTO'.
       01 WS-STATUS            PIC X VALUE 'A'.

Sem uma inicialização adequada, o programa pode trabalhar com conteúdo inesperado.

Em muitos ambientes, determinadas áreas podem receber valores previsíveis conforme o compilador, o runtime e a forma de carregamento. Porém, um programa profissional não deve depender de suposições frágeis.

Sempre que o valor inicial for importante, declare-o ou inicialize-o explicitamente.

       INITIALIZE WS-AREA-TRABALHO

Mas investigue o uso de INITIALIZE com cuidado: ele não é necessariamente equivalente a mover espaços ou zeros para todos os campos indiscriminadamente. Seu comportamento respeita as categorias dos itens e pode ser alterado com cláusulas adicionais.


LOCAL-STORAGE SECTION: cada chamada recebe uma cena isolada

A LOCAL-STORAGE SECTION é semelhante à Working-Storage, mas possui uma diferença essencial: suas áreas são alocadas para cada ativação do programa.

       LOCAL-STORAGE SECTION.

       01 LS-CONTADOR          PIC 9(5) VALUE ZERO.
       01 LS-MENSAGEM          PIC X(40).

Em termos conceituais:

Primeira chamada:
LS-CONTADOR próprio

Segunda chamada:
LS-CONTADOR próprio

Terceira chamada:
LS-CONTADOR próprio

Cada invocação recebe seu próprio conjunto de dados locais.

Isso é especialmente útil em:

  • programas reentrantes;

  • rotinas reutilizáveis;

  • ambientes com várias chamadas simultâneas;

  • aplicações servidoras;

  • processamento sob Language Environment;

  • componentes que não devem preservar estado entre ativações.

Working-Storage versus Local-Storage

Uma simplificação útil:

CaracterísticaWorking-StorageLocal-Storage
ExistênciaAssociada à instância carregada do programaCriada para cada invocação
InicializaçãoNormalmente ocorre quando o programa é carregadoOcorre em cada entrada
Uso típicoEstado geral, constantes, áreas persistentes durante execuçãoDados privados de uma chamada
ReentrânciaExige maior cuidadoFacilita isolamento por ativação

Entretanto, não reduza a discussão a “Working-Storage é compartilhada e Local-Storage nunca é”.

O comportamento real depende de fatores como:

  • forma de chamada;

  • programas estáticos ou dinâmicos;

  • uso de CANCEL;

  • opções de compilação;

  • ambiente CICS;

  • atributos de reentrância;

  • runtime;

  • arquitetura da aplicação.

No laboratório do mainframe, frases absolutas são frequentemente suspeitas.


Um caso clássico: o contador que se recusava a voltar para zero

Imagine um subprograma:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CALCULA01.

       DATA DIVISION.

       WORKING-STORAGE SECTION.

       01 WS-CONTADOR          PIC 9(4) VALUE ZERO.

       PROCEDURE DIVISION.

           ADD 1 TO WS-CONTADOR
           DISPLAY 'CONTADOR: ' WS-CONTADOR

           GOBACK.

O programa chamador executa várias chamadas.

Um iniciante pode esperar:

CONTADOR: 0001
CONTADOR: 0001
CONTADOR: 0001

Mas, dependendo da forma de carregamento e das condições de execução, pode observar:

CONTADOR: 0001
CONTADOR: 0002
CONTADOR: 0003

Isso ocorre porque a Working-Storage pode manter seu conteúdo entre chamadas enquanto o programa permanecer carregado.

Mover o contador para Local-Storage muda a intenção:

       LOCAL-STORAGE SECTION.

       01 LS-CONTADOR          PIC 9(4) VALUE ZERO.

Agora cada chamada recebe uma nova área inicializada.

Esse tipo de comportamento parece sobrenatural apenas até encontrarmos a seção correta.

Depois disso, torna-se evidência técnica.


LINKAGE SECTION: dados que pertencem a outra pessoa

A LINKAGE SECTION descreve dados fornecidos por outra unidade de execução.

Esses dados não são, em princípio, áreas comuns criadas e pertencentes ao subprograma da mesma forma que itens da Working-Storage.

Exemplo de programa chamador:

       WORKING-STORAGE SECTION.

       01 WS-CLIENTE.
           05 WS-CODIGO        PIC 9(5).
           05 WS-NOME          PIC X(30).
           05 WS-SALDO         PIC S9(7)V99 COMP-3.

       PROCEDURE DIVISION.

           MOVE 12345 TO WS-CODIGO
           MOVE 'STELLA BONASERA' TO WS-NOME
           MOVE 1500.75 TO WS-SALDO

           CALL 'ATUALIZA1'
               USING WS-CLIENTE

           GOBACK.

Programa chamado:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. ATUALIZA1.

       DATA DIVISION.

       LINKAGE SECTION.

       01 LK-CLIENTE.
           05 LK-CODIGO        PIC 9(5).
           05 LK-NOME          PIC X(30).
           05 LK-SALDO         PIC S9(7)V99 COMP-3.

       PROCEDURE DIVISION USING LK-CLIENTE.

           ADD 100 TO LK-SALDO

           GOBACK.

O chamador entrega uma área.

O subprograma descreve essa área na Linkage Section.

A PROCEDURE DIVISION USING estabelece a associação entre os argumentos recebidos e os itens de Linkage.


BY REFERENCE, BY CONTENT e BY VALUE

O método de passagem de parâmetros muda completamente a investigação.

BY REFERENCE

É a forma tradicional e muito comum.

       CALL 'ATUALIZA1'
           USING BY REFERENCE WS-CLIENTE

O subprograma recebe acesso à área do chamador.

Alterações podem ser percebidas pelo chamador.

Chamador possui WS-SALDO
        |
        v
Subprograma acessa a mesma área
        |
        v
Alteração volta para o chamador

BY CONTENT

O subprograma recebe uma cópia lógica do argumento.

       CALL 'CONSULTA1'
           USING BY CONTENT WS-CLIENTE

O programa chamado pode trabalhar com o conteúdo, mas mudanças não devem retornar para a área original como numa passagem por referência.

BY VALUE

Utilizado para passar o valor diretamente, sendo especialmente relevante na interoperabilidade com outras linguagens e APIs.

       CALL 'ROTINAC'
           USING BY VALUE WS-CODIGO

BY VALUE exige atenção a tamanho, representação e convenções de chamada.

Não basta o número “parecer igual”. Os bytes precisam ser compatíveis.

Em integração, o assassino frequentemente se chama “layout incompatível”.


O contrato precisa ser idêntico

Considere o chamador:

       01 WS-CLIENTE.
           05 WS-CODIGO        PIC 9(5).
           05 WS-NOME          PIC X(30).
           05 WS-SALDO         PIC S9(7)V99 COMP-3.

E o chamado:

       01 LK-CLIENTE.
           05 LK-CODIGO        PIC 9(5).
           05 LK-NOME          PIC X(20).
           05 LK-SALDO         PIC S9(7)V99 COMP-3.

O nome possui 30 bytes no chamador, mas apenas 20 na visão do chamado.

Isso desloca o campo seguinte.

O subprograma pode interpretar os últimos dez bytes do nome como parte do saldo.

Não existe magia.

Existe desalinhamento.

Em sistemas reais, esse erro pode gerar:

  • valores corrompidos;

  • dados aparentemente aleatórios;

  • S0C7;

  • sobreposição de campos;

  • gravações incorretas;

  • falhas intermitentes;

  • resultados diferentes após recompilações.

Por isso copybooks compartilhados são tão importantes.


COPYBOOK: o laudo oficial do layout

Em vez de repetir a mesma estrutura em dezenas de programas, podemos centralizá-la em um copybook.

Arquivo CPYCLI01:

       01 CLIENTE-DADOS.
           05 CLIENTE-CODIGO   PIC 9(5).
           05 CLIENTE-NOME     PIC X(30).
           05 CLIENTE-SALDO    PIC S9(7)V99 COMP-3.

No chamador:

       WORKING-STORAGE SECTION.

       COPY CPYCLI01.

No chamado:

       LINKAGE SECTION.

       COPY CPYCLI01.

Assim, ambos utilizam a mesma definição.

Mas existe uma armadilha: alterar o copybook e recompilar apenas um dos programas.

O fonte parece correto.

O copybook parece correto.

O programa recompilado parece correto.

Mas o módulo antigo continua esperando o layout anterior.

E então nasce um crime perfeito: duas versões corretas individualmente, incompatíveis quando trabalham juntas.

A solução envolve disciplina de gestão de dependências, recompilação, testes e controle de versões.


SCREEN SECTION: a antiga sala de interrogatório

A SCREEN SECTION permite definir telas em implementações COBOL que oferecem esse recurso.

Exemplo genérico:

       SCREEN SECTION.

       01 TELA-CLIENTE.
           05 BLANK SCREEN.
           05 LINE 3 COLUMN 10
              VALUE 'CODIGO DO CLIENTE:'.
           05 LINE 3 COLUMN 30
              PIC 9(5)
              USING WS-CODIGO.

Ela foi utilizada em sistemas interativos de diversas plataformas.

No universo IBM mainframe, especialmente em aplicações CICS, interfaces 3270 são frequentemente definidas por mapas BMS.

Em IMS, pode-se encontrar MFS.

Em arquiteturas modernas, o COBOL pode funcionar atrás de:

  • APIs REST;

  • aplicações web;

  • serviços de integração;

  • mensageria;

  • z/OS Connect;

  • CICS Transaction Gateway;

  • aplicativos móveis.

A tela pode ter desaparecido do COBOL, mas o programa continua processando o coração da transação.


REPORT SECTION: o especialista aposentado que ainda sabe demais

A REPORT SECTION está associada ao Report Writer, um recurso criado para facilitar a produção de relatórios estruturados.

Ela podia ajudar a organizar:

  • cabeçalhos;

  • detalhes;

  • rodapés;

  • totais;

  • quebras de grupo;

  • paginação.

Exemplo conceitual:

       REPORT SECTION.

       RD RELATORIO-VENDAS.

       01 TYPE IS PAGE HEADING.
          05 COLUMN 1 PIC X(20)
             VALUE 'RELATORIO DE VENDAS'.

Atualmente, muitos relatórios são produzidos por:

  • programas tradicionais;

  • DFSORT;

  • ferramentas de BI;

  • bancos de dados;

  • aplicações distribuídas;

  • geradores de documentos;

  • plataformas analíticas.

Mesmo assim, sistemas antigos podem utilizar Report Writer até hoje.

Em mainframe, “antigo” não significa necessariamente “inútil”.

Às vezes significa apenas “estável há 35 anos e ainda fechando a contabilidade antes do amanhecer”.


A hierarquia dos níveis: reconstruindo o corpo do registro

COBOL utiliza números de nível para representar a hierarquia dos dados.

       01 WS-CLIENTE.
           05 WS-IDENTIFICACAO.
               10 WS-CODIGO    PIC 9(5).
               10 WS-CPF       PIC 9(11).
           05 WS-NOME          PIC X(30).
           05 WS-ENDERECO.
               10 WS-RUA       PIC X(30).
               10 WS-NUMERO    PIC 9(5).
               10 WS-CIDADE    PIC X(20).

Visualmente:

WS-CLIENTE
├── WS-IDENTIFICACAO
│   ├── WS-CODIGO
│   └── WS-CPF
├── WS-NOME
└── WS-ENDERECO
    ├── WS-RUA
    ├── WS-NUMERO
    └── WS-CIDADE

Os itens de grupo não possuem PIC.

Eles são formados pelos campos subordinados.

Podemos mover ou exibir o grupo inteiro:

       DISPLAY WS-CLIENTE

Mas isso manipula a sequência física dos bytes, não uma abstração independente.


Os níveis especiais

Além dos níveis comuns, COBOL possui níveis especiais.

Nível 01

Define uma estrutura principal ou registro.

       01 WS-CLIENTE.

Níveis 02 a 49

Definem itens subordinados.

           05 WS-NOME PIC X(30).

Nível 66

Utilizado com RENAMES.

       66 WS-DADOS-BASICOS RENAMES
          WS-CODIGO THRU WS-NOME.

Hoje é pouco usado e deve ser tratado com cuidado, pois pode dificultar a leitura.

Nível 77

Define um item elementar independente.

       77 WS-CONTADOR PIC 9(5).

Ainda pode ser encontrado em programas antigos, embora muitos padrões modernos prefiram organizar itens sob níveis 01.

Nível 78

Em algumas implementações, é utilizado para constantes de compilação.

Sua disponibilidade e detalhes dependem do compilador.

Nível 88

Define nomes de condição.

           88 CLIENTE-ATIVO VALUE 'A'.

PICTURE: o retrato falado do dado

A cláusula PIC, abreviação de PICTURE, descreve a categoria e o formato do campo.

Alfanumérico

       05 WS-NOME PIC X(30).

Pode conter letras, números, espaços e outros caracteres compatíveis com a codificação utilizada.

Numérico

       05 WS-IDADE PIC 9(3).

Representa três posições numéricas.

Alfabético

       05 WS-INICIAL PIC A.

Seu uso é menos comum em programas modernos.

Com sinal

       05 WS-SALDO PIC S9(7)V99.

O S indica sinal.

Decimal implícito

       05 WS-VALOR PIC 9(5)V99.

O V não ocupa uma posição física.

Ele indica onde o programa deve interpretar a casa decimal.

O valor:

0012345

pode ser interpretado como:

123,45

de acordo com o layout.

Esse é um dos grandes suspeitos em integrações.

Se um sistema envia centavos e outro espera reais, um pagamento de R$ 150,00 pode ser interpretado como R$ 15.000,00 ou R$ 1,50.

O byte está correto.

A interpretação está errada.


DISPLAY, COMP, COMP-3: mesma informação, corpos diferentes

Um número pode possuir diferentes representações internas.

DISPLAY

       05 WS-VALOR PIC 9(5).

Cada dígito costuma ocupar uma posição de caractere.

COMP ou BINARY

       05 WS-VALOR PIC S9(9) COMP.

O valor é armazenado em representação binária conforme as regras do compilador e opções aplicáveis.

COMP-3

       05 WS-VALOR PIC S9(7)V99 COMP-3.

Utiliza decimal compactado.

Dois dígitos normalmente são armazenados por byte, com uma parte do último byte usada para o sinal.

É muito comum em aplicações financeiras porque representa valores decimais com precisão e economia de espaço.

A pista do S0C7

Um S0C7 normalmente aponta para uma exceção de dados durante uma operação decimal.

Causas comuns:

  • campo numérico contém bytes inválidos;

  • layout incorreto;

  • deslocamento provocado por copybook incompatível;

  • campo não inicializado;

  • arquivo lido com definição errada;

  • tentativa de calcular usando dados alfanuméricos;

  • erro de REDEFINES;

  • parâmetros desalinhados.

O erro aparece na Procedure Division porque uma instrução tentou utilizar o campo.

Mas o verdadeiro criminoso pode estar na Data Division.


REDEFINES: duas interpretações para a mesma evidência

REDEFINES permite que a mesma área de memória seja vista de maneiras diferentes.

       01 WS-DATA-NUMERICA.
           05 WS-DATA-AAAAMMDD PIC 9(8).

       01 WS-DATA-DETALHADA
          REDEFINES WS-DATA-NUMERICA.
           05 WS-ANO           PIC 9(4).
           05 WS-MES           PIC 9(2).
           05 WS-DIA           PIC 9(2).

Se:

       MOVE 20260725 TO WS-DATA-AAAAMMDD

então podemos acessar:

WS-ANO = 2026
WS-MES = 07
WS-DIA = 25

Nenhum dado foi copiado.

A mesma sequência de bytes recebeu duas descrições.

É poderoso, eficiente e perigoso.

Um REDEFINES incorreto pode transformar:

  • nome em número;

  • data em saldo;

  • código em endereço;

  • payload em campos incompatíveis.

No CSI do mainframe, REDEFINES é aquele suspeito elegante que parece sempre ter um álibi.


OCCURS: a formação da quadrilha

OCCURS define repetições de uma estrutura, criando tabelas.

       01 WS-TABELA-CLIENTES.
           05 WS-CLIENTE OCCURS 100 TIMES.
               10 WS-CODIGO    PIC 9(5).
               10 WS-NOME      PIC X(30).

Isso reserva espaço para cem ocorrências.

Podemos acessar:

       MOVE 12345 TO WS-CODIGO (1)
       MOVE 'MAC TAYLOR' TO WS-NOME (1)

Subscript

       01 WS-I PIC 9(3) COMP VALUE 1.

       DISPLAY WS-NOME (WS-I)

Index

A tabela pode ser definida com índice:

       05 WS-CLIENTE OCCURS 100 TIMES
           INDEXED BY IDX-CLIENTE.

Uso:

       SET IDX-CLIENTE TO 1
       DISPLAY WS-NOME (IDX-CLIENTE)

O índice possui natureza própria e pode ser otimizado para o deslocamento interno da tabela.

Nunca ultrapasse os limites do OCCURS.

Acessar a ocorrência 101 de uma tabela com cem elementos pode atingir memória pertencente a outro campo.

É o equivalente digital de atravessar a fita amarela da cena do crime.


Passo a passo: montando um programa completo

Vamos construir um pequeno processamento sequencial.

1. Declarar o arquivo no ambiente

       ENVIRONMENT DIVISION.

       INPUT-OUTPUT SECTION.

       FILE-CONTROL.

           SELECT ARQ-CLIENTES
               ASSIGN TO CLIENTES
               ORGANIZATION IS SEQUENTIAL
               FILE STATUS IS WS-FILE-STATUS.

2. Descrever o registro

       DATA DIVISION.

       FILE SECTION.

       FD  ARQ-CLIENTES.

       01  REG-CLIENTE.
           05 REG-CODIGO       PIC 9(5).
           05 REG-NOME         PIC X(30).
           05 REG-SALDO        PIC S9(7)V99 COMP-3.

3. Criar áreas auxiliares

       WORKING-STORAGE SECTION.

       01 WS-FILE-STATUS       PIC XX.

       01 WS-CONTROLES.
           05 WS-FIM           PIC X VALUE 'N'.
               88 FIM-ARQUIVO  VALUE 'S'.
               88 HA-REGISTRO  VALUE 'N'.

       01 WS-TOTAIS.
           05 WS-QTD           PIC 9(7) VALUE ZERO.
           05 WS-TOTAL-SALDO   PIC S9(13)V99 COMP-3
                               VALUE ZERO.

4. Abrir o arquivo

       PROCEDURE DIVISION.

       0000-PRINCIPAL.

           OPEN INPUT ARQ-CLIENTES

           IF WS-FILE-STATUS NOT = '00'
               DISPLAY 'ERRO NO OPEN: ' WS-FILE-STATUS
               MOVE 12 TO RETURN-CODE
               GOBACK
           END-IF

5. Ler o primeiro registro

           PERFORM 1000-LER-CLIENTE

6. Processar até o fim

           PERFORM UNTIL FIM-ARQUIVO

               ADD 1 TO WS-QTD
               ADD REG-SALDO TO WS-TOTAL-SALDO

               DISPLAY REG-CODIGO
                       ' '
                       REG-NOME

               PERFORM 1000-LER-CLIENTE

           END-PERFORM

7. Encerrar

           CLOSE ARQ-CLIENTES

           DISPLAY 'CLIENTES: ' WS-QTD
           DISPLAY 'TOTAL:    ' WS-TOTAL-SALDO

           GOBACK.

8. Criar o parágrafo de leitura

       1000-LER-CLIENTE.

           READ ARQ-CLIENTES
               AT END
                   SET FIM-ARQUIVO TO TRUE
               NOT AT END
                   SET HA-REGISTRO TO TRUE
           END-READ.

O programa completo demonstra como cada seção coopera.

A File Section fornece o registro.

A Working-Storage guarda o controle e os totais.

A Procedure Division conduz o processamento.

Cada elemento possui responsabilidade própria.


Checklist forense para analisar uma DATA DIVISION

Quando um programa apresenta erro de dados, examine:

1. O PIC está correto?

Compare tamanho, sinal e casas decimais.

PIC 9(7)V99

não é equivalente a:

PIC 9(9)

2. O formato interno é compatível?

PIC S9(7)V99 COMP-3

não possui a mesma representação física de:

PIC X(5)

3. O arquivo está com o LRECL esperado?

Se o programa espera 100 bytes, mas o arquivo possui 120, parte do registro pode ser ignorada ou interpretada incorretamente.

4. O copybook é a versão correta?

Verifique data, biblioteca, concatenação e versão usada na compilação.

5. Chamador e chamado foram recompilados?

Uma mudança na interface pode exigir recompilar todos os consumidores.

6. Existe REDEFINES?

Descubra qual visão está sendo usada em cada ponto.

7. Existe OCCURS?

Verifique limites, índices e subscritos.

8. O campo foi inicializado?

Não presuma que contém zeros ou espaços.

9. O parâmetro foi passado pelo método correto?

Confirme BY REFERENCE, BY CONTENT ou BY VALUE.

10. O campo possui alinhamento ou sincronização especial?

Cláusulas como SYNCHRONIZED podem introduzir bytes de preenchimento dependendo do compilador e da estrutura.


Curiosidades da sala de evidências

Curiosidade 1: o nome do campo não existe no arquivo

Um arquivo físico não contém necessariamente nomes como:

REG-CODIGO
REG-NOME
REG-SALDO

Ele contém bytes.

Os nomes existem no programa para que os humanos e o compilador interpretem as posições.

O mesmo arquivo pode receber layouts diferentes.

Um deles estará correto.

Os demais produzirão ficção científica.

Curiosidade 2: PIC não é uma máscara de exibição apenas

Muitos iniciantes associam PICTURE apenas à aparência.

Na verdade, ela define categoria, tamanho e interpretação do item.

Curiosidade 3: o ponto decimal pode não existir fisicamente

No V implícito, nenhum caractere de ponto ou vírgula é armazenado.

PIC 9(5)V99

ocupa sete dígitos, não oito posições contendo um separador.

Curiosidade 4: um item de grupo pode misturar categorias

       01 WS-REGISTRO.
           05 WS-CODIGO PIC 9(5).
           05 WS-NOME   PIC X(20).

O grupo inteiro pode ser tratado como uma sequência de bytes para certas operações, apesar de conter campos de diferentes categorias.

Curiosidade 5: a memória é inocente

A memória não sabe que aqueles bytes representam CPF, saldo ou data.

Ela apenas armazena bits.

O significado vem do layout.

Quando o layout mente, a memória obedece.


Easter eggs do laboratório CSI Mainframe

Em homenagem ao clima de investigação, os nomes dos exemplos esconderam algumas referências.

  • MAC TAYLOR aparece como líder da equipe forense de Nova York.

  • STELLA BONASERA foi usada em uma estrutura de cliente.

  • O horário de 02h17 lembra a rotina dos processamentos batch que terminam quando a cidade dorme.

  • O terminal 3270 funciona como a mesa de autópsia digital.

  • O S0C7 é o equivalente mainframe de encontrar uma impressão digital impossível na arma do crime.

  • O copybook incompatível é o “suspeito que possuía duas identidades”.

  • O REDEFINES representa a evidência que muda de aparência dependendo do ângulo da luz.

  • O OCCURS é a fotografia de uma quadrilha perfeitamente alinhada na parede do distrito policial.

E existe um easter egg maior.

Em quase todo mistério COBOL, o programador procura primeiro a linha que falhou.

O investigador experiente procura primeiro o dado que chegou até ela.


Dicas do Bellacosa Mainframe para o iniciante

Use nomes que revelem intenção

Evite:

       01 X1 PIC X.

Prefira:

       01 WS-STATUS-CLIENTE PIC X.

Agrupe campos relacionados

       01 WS-CONTROLES.
           05 WS-FIM-ARQUIVO PIC X.
           05 WS-ERRO        PIC X.
           05 WS-RETORNO     PIC 9(4).

Use níveis 88

Eles tornam o código mais claro e reduzem comparações espalhadas.

Padronize prefixos

Exemplo:

  • WS- para Working-Storage;

  • LS- para Local-Storage;

  • LK- para Linkage;

  • REG- para registros de arquivo;

  • CT- para constantes;

  • IDX- para índices.

Isso não é uma regra universal da linguagem, mas ajuda muito na leitura.

Documente formatos numéricos

Especialmente:

  • sinal;

  • casas decimais;

  • COMP;

  • COMP-3;

  • valores enviados a outros sistemas.

Trate copybooks como interfaces

Uma alteração em copybook não é apenas uma mudança de layout.

Pode ser uma mudança de contrato entre dezenas ou centenas de programas.

Nunca ignore o tamanho total

Calcule o comprimento do registro.

Confirme com:

  • LRECL;

  • documentação;

  • catálogo;

  • ferramenta de browse;

  • definição do dataset;

  • programa produtor;

  • programa consumidor.

Teste limites

Para OCCURS, teste:

  • primeira posição;

  • última posição válida;

  • tabela vazia;

  • tabela completa;

  • tentativa de ultrapassagem;

  • chave não encontrada.


A conclusão da investigação

A equipe se reúne diante do painel de vidro.

O programa não falhou porque o ADD estava errado.

A instrução era perfeitamente válida.

O problema estava em um copybook antigo usado por um subprograma que não havia sido recompilado.

O chamador enviava:

       05 CLIENTE-NOME PIC X(30).

O chamado ainda esperava:

       05 CLIENTE-NOME PIC X(20).

Os dez bytes excedentes deslocaram o saldo.

Quando o programa tentou somar aquele conteúdo como decimal compactado, ocorreu o S0C7.

A linha da Procedure Division apenas encontrou o corpo.

O crime havia sido planejado na Data Division.

Essa é a lição central.

A DATA DIVISION não é um depósito passivo de declarações. Ela é a fundação arquitetural do programa COBOL.

A FILE SECTION descreve os registros que chegam de arquivos.

A WORKING-STORAGE SECTION mantém controles, acumuladores, tabelas e áreas utilizadas durante a execução.

A LOCAL-STORAGE SECTION fornece áreas independentes para cada ativação.

A LINKAGE SECTION estabelece contratos de comunicação entre programas.

A SCREEN SECTION pode descrever interfaces interativas.

A REPORT SECTION pode organizar relatórios estruturados.

Os níveis constroem hierarquias.

A cláusula PIC define formatos.

VALUE estabelece estados iniciais.

OCCURS cria tabelas.

REDEFINES oferece diferentes interpretações para a mesma memória.

Os níveis 88 transformam códigos em significado.

COMP e COMP-3 revelam que dois campos numericamente semelhantes podem possuir corpos físicos completamente diferentes.

Para o programador iniciante, dominar a Data Division significa começar a enxergar além da aparência do código.

Você deixa de ver apenas:

       05 SALDO PIC S9(7)V99 COMP-3.

E passa a enxergar:

Campo assinado
Decimal
Sete posições inteiras
Duas casas decimais
Representação compactada
Contrato físico de armazenamento
Possível ponto de integração
Possível origem de S0C7
Possível incompatibilidade com copybook

Esse é o momento em que o estudante deixa de apenas escrever COBOL e começa a investigar sistemas.

Porque na programação corporativa os defeitos raramente anunciam sua origem.

Eles aparecem em outro módulo.

Falham horas depois.

Dependem de um registro específico.

Só acontecem em produção.

Desaparecem durante o teste.

Retornam no fechamento mensal.

E deixam para trás apenas um dump, um código de retorno, algumas mensagens no spool e um campo cheio de bytes que ninguém deveria ter interpretado daquela maneira.

Mas não se preocupe.

Coloque as luvas.

Abra o compile listing.

Verifique o offset.

Compare o copybook.

Calcule o comprimento.

Analise o formato.

Siga o rastro dos bytes.

No laboratório do Bellacosa Mainframe, toda variável possui uma história.

Todo registro possui um passado.

Todo ABEND possui uma causa.

E toda Data Division, quando examinada com atenção, acaba confessando.

Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...