Translate

Mostrar mensagens com a etiqueta language environment. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta language environment. Mostrar todas as mensagens

quinta-feira, 2 de julho de 2026

As 16 Recomendações da IBM que Todo Programador COBOL Padawan Deveria Conhecer

 

Bellacosa Mainframe e 16 recomendacoes Jedi para seu programa COBOL século XXI

☕ Um Café no Bellacosa Mainframe

As 16 Recomendações da IBM que Todo Programador COBOL Padawan Deveria Conhecer

Da Era dos Cartões Perfurados ao IBM Z Moderno: Como Escrever COBOL Preparado para os Próximos 30 Anos

"A maior diferença entre um Programador COBOL Júnior e um Arquiteto Mainframe não está em quantos comandos ele conhece, mas em entender por que a linguagem evoluiu."

Existe uma frase muito comum entre desenvolvedores iniciantes:

"Sempre fizemos assim."

Ela parece inofensiva.

Mas, no mundo Mainframe, ela pode esconder décadas de dívida técnica.

Muitos sistemas COBOL que ainda executam hoje foram escritos quando:

  • o IBM System/360 ainda era novidade;

  • cartões perfurados eram utilizados;

  • memória era medida em kilobytes;

  • não existia Internet;

  • não existia Java;

  • não existia JSON;

  • ninguém imaginava APIs REST.

Mesmo assim, esses sistemas continuam processando bilhões de dólares diariamente.

Então surge uma pergunta inevitável:

Se eles funcionam tão bem, por que a IBM continua evoluindo o COBOL?

A resposta é simples.

Porque o mundo mudou.

O hardware mudou.

Os processadores IBM Z mudaram.

O Language Environment (LE) mudou.

As aplicações passaram a conversar com Java, Python, Node.js, microsserviços, OpenShift, APIs REST e serviços em nuvem.

O COBOL também precisou evoluir.

E é exatamente isso que veremos neste café.


A filosofia da IBM

Existe um detalhe curioso.

A IBM raramente muda uma linguagem apenas porque existe uma novidade tecnológica.

Ela muda quando existe ganho real.

Os princípios normalmente são:

  • mais segurança

  • mais desempenho

  • menos CPU

  • menos manutenção

  • melhor integração

  • melhor diagnóstico

  • maior reutilização

Sempre que surgir uma recomendação da IBM, pergunte:

"Qual problema essa mudança resolveu?"

Essa pergunta transforma um Padawan em um profissional que entende arquitetura.


1. STOP RUN → GOBACK

Provavelmente a recomendação mais conhecida.

Durante décadas escrevíamos:

STOP RUN.

Hoje, novos projetos costumam utilizar:

GOBACK.

Por quê?

Imagine um restaurante.

Você pede um café.

O garçom leva até sua mesa.

Quando termina de beber, o correto é devolver a xícara ao garçom.

Não faz sentido fechar o restaurante inteiro.

Foi exatamente isso que aconteceu com o COBOL.

Nos anos 60 o programa era praticamente o dono da execução.

Hoje ele normalmente é apenas um componente.

Pode ser chamado por:

  • outro COBOL

  • CICS

  • IMS

  • Java

  • API REST

  • MQ

  • z/OS Connect

Se um módulo chamado executar STOP RUN...

Toda a Run Unit termina.

Com GOBACK...

O controle simplesmente retorna ao chamador.

Dica Bellacosa

Sempre imagine:

"Meu programa está prestando um serviço."

Quem chamou deve decidir quando terminar a aplicação.


2. NUMCHECK

Todo programador já viu um S0C7.

Normalmente ele aparece na madrugada.

Em produção.

Na sexta-feira.

O motivo quase sempre é simples.

Dados inválidos.

Exemplo:

MOVE "ABC" TO WS-VALOR.
ADD 10 TO WS-VALOR.

Visualmente parece correto.

Na prática...

Explode.

NUMCHECK faz o compilador inserir verificações para identificar esse tipo de problema antes que ele vire um incidente.

Curiosidade

Muitos S0C7 não nascem onde ocorrem.

O dado inválido pode ter sido gravado horas antes por outro programa.


3. SSRANGE

Imagine um armário com 100 gavetas.

Você tenta abrir a gaveta 101.

Ela simplesmente não existe.

Sem SSRANGE...

Seu programa pode acessar memória indevida.

Com SSRANGE...

O erro é detectado imediatamente.

Exemplo:

01 TABELA.
   05 ITEM OCCURS 100 TIMES.

MOVE "X" TO ITEM(101).

Esse erro pode permanecer escondido durante anos.

Até que um dia...

Produção.


Curiosidade

Grande parte dos erros difíceis de reproduzir está relacionada ao acesso indevido de memória.

SSRANGE ajuda justamente nisso.


4. TEST

Quantos DISPLAY você já encontrou em produção?

DISPLAY "CHEGUEI AQUI".

DISPLAY SQLCODE.

DISPLAY WS-CLIENTE.

Eles ajudam?

Sim.

Mas apenas temporariamente.

Hoje existem ferramentas de Debug muito mais completas.

Com TEST, o programa pode ser analisado sem transformar o código em uma árvore de DISPLAY.


5. Unicode

Durante décadas tudo era EBCDIC.

Hoje recebemos:

  • JSON

  • XML

  • APIs

  • Web

  • Smartphones

  • Emojis

  • Idiomas internacionais

O COBOL moderno suporta Unicode.

Isso significa muito mais integração.

Imagine um banco atendendo clientes no Japão, Brasil e Alemanha.

Tudo utilizando a mesma aplicação.


Curiosidade

Muitos desenvolvedores COBOL nunca perceberam que o Enterprise COBOL moderno possui excelente suporte a Unicode.


6. JSON PARSE

Há alguns anos montar JSON significava algo parecido com isto:

STRING "{"

...

"}"

Muito código.

Muito risco.

Muito difícil de manter.

Hoje basta utilizar:

JSON GENERATE.

Ou

JSON PARSE.

O compilador faz praticamente todo o trabalho.


Isso muda completamente a modernização

Imagine integrar COBOL com:

  • React

  • Angular

  • Flutter

  • Java

  • Python

JSON virou a linguagem universal.


7. XML PARSE

O mesmo aconteceu com XML.

Antes era comum utilizar:

UNSTRING.

INSPECT.

STRING.

Hoje o compilador entende XML nativamente.

Menos código.

Menos bugs.

Mais produtividade.


8. RENT

Talvez uma das opções menos conhecidas pelos iniciantes.

RENT significa:

Reentrant.

Ou seja...

O programa pode ser executado simultaneamente por diversos usuários.

Imagine um banco.

Cinco mil clientes consultando saldo.

O mesmo programa atende todos.

Isso só funciona porque ele foi escrito corretamente.


Dica

Sempre evite gravar informações temporárias em áreas compartilhadas.


9. DYNAM

No passado quase tudo era ligado durante o Link-Edit.

Hoje queremos mais flexibilidade.

CALL dinâmico permite substituir módulos sem reconstruir toda a aplicação.

É um grande aliado em ambientes modernos.


10. EVALUATE

Existe um momento na vida de todo Padawan em que ele escreve isto:

IF
ELSE
IF
ELSE
IF
ELSE

Depois de alguns meses...

Nem ele entende mais.

EVALUATE resolve exatamente isso.

Exemplo:

EVALUATE WS-TIPO

WHEN 1

WHEN 2

WHEN 3

WHEN OTHER

END-EVALUATE

Muito mais limpo.


11. END-IF

Antigamente muitos programas dependiam de ponto final e NEXT SENTENCE.

Isso gerava ambiguidades.

Hoje escrevemos:

IF ...

END-IF

O compilador entende exatamente onde cada bloco termina.


12. Intrinsic Functions

Durante muitos anos criávamos rotinas para tudo.

Hoje o compilador já oferece dezenas de funções.

Exemplos:

FUNCTION CURRENT-DATE

FUNCTION LENGTH

FUNCTION TRIM

FUNCTION LOWER-CASE

FUNCTION UPPER-CASE

Além de deixar o código mais elegante, elas costumam ser mais eficientes.


13. Evitar ALTER

ALTER era considerado brilhante.

Na década de 70.

Hoje virou pesadelo.

Ele altera dinamicamente o fluxo do programa.

Resultado:

  • difícil de entender;

  • difícil de depurar;

  • difícil de otimizar.

Por isso praticamente desapareceu dos novos projetos.


14. Reduzir GO TO

Existe um mito.

GO TO não é proibido.

Mas o excesso dele transforma um programa em um labirinto.

Imagine tentar seguir uma história cuja página seguinte muda aleatoriamente.

É exatamente essa sensação.

PERFORM e EVALUATE tornam o fluxo muito mais claro.


15. Migrar para Enterprise COBOL 6.x

Essa talvez seja a maior evolução dos últimos anos.

O compilador moderno entende muito melhor os processadores IBM Z atuais.

Isso significa:

  • menos CPU;

  • otimizações automáticas;

  • melhores diagnósticos;

  • suporte ampliado a JSON e XML;

  • novas funções intrínsecas.

Em muitos casos, apenas recompilar um programa com ajustes adequados já produz ganhos perceptíveis de desempenho.


16. Pensar em Integração

Esta talvez seja a maior mudança cultural.

Antes escrevíamos programas Batch.

Hoje escrevemos serviços corporativos.

Um programa COBOL pode atender:

  • Mobile Banking

  • Internet Banking

  • PIX

  • APIs REST

  • Java

  • Python

  • Node.js

  • OpenShift

  • Mensageria MQ

O código precisa nascer preparado para esse mundo.


O impacto nos programas antigos

A boa notícia é que a IBM sempre valorizou compatibilidade. Muitos programas escritos há décadas ainda compilam e executam nas versões atuais do Enterprise COBOL.

Isso, porém, não significa que estejam aproveitando os recursos modernos.

É comum encontrar aplicações com:

  • STOP RUN em todos os módulos;

  • dezenas de GO TO;

  • ALTER;

  • manipulação manual de XML e JSON;

  • ausência de verificações de dados;

  • poucas opções de diagnóstico.

Esses programas continuam funcionando, mas tendem a ser mais difíceis de manter, testar e integrar.

Modernizar não significa reescrever tudo. Em muitos casos, basta evoluir gradualmente: substituir comandos antigos, ativar opções do compilador, introduzir funções intrínsecas e organizar melhor o código.


A evolução de um Programador COBOL

Todo desenvolvedor passa por etapas.

Padawan

Aprende a sintaxe.

Consegue compilar.

Resolve problemas.

Programador

Começa a reutilizar código.

Escreve módulos.

Documenta interfaces.

Desenvolvedor Sênior

Pensa em desempenho.

CPU.

Memória.

Escalabilidade.

Arquiteto

Pensa no sistema inteiro.

Integração.

Disponibilidade.

Evolução.

Governança.

Perceba que, à medida que você cresce, a linguagem deixa de ser o foco principal. O importante passa a ser a qualidade das decisões.


O Mainframe moderno

Existe um mito antigo de que o Mainframe "parou no tempo".

Nada poderia estar mais distante da realidade.

Hoje um IBM Z pode:

  • expor APIs REST;

  • consumir serviços externos;

  • executar aplicações Java;

  • trabalhar com contêineres;

  • integrar-se ao OpenShift;

  • processar JSON e XML;

  • utilizar DevOps, Git e pipelines CI/CD;

  • compartilhar dados em tempo real com aplicações distribuídas.

O COBOL moderno acompanha essa evolução. As recomendações da IBM existem justamente para que o código continue relevante nesse novo cenário.


Conclusão

Existe uma frase que resume toda essa evolução:

"O melhor código não é aquele que apenas funciona hoje; é aquele que continuará funcionando, sendo compreendido e evoluído daqui a vinte anos."

As recomendações da IBM não representam uma ruptura com o passado. Elas representam a continuidade de uma filosofia que sempre guiou o Mainframe: estabilidade, desempenho, confiabilidade e evolução gradual.

Trocar STOP RUN por GOBACK, utilizar NUMCHECK, adotar SSRANGE nos testes, explorar JSON PARSE, JSON GENERATE, XML PARSE, RENT, funções intrínsecas e estruturas mais legíveis não é seguir uma moda. É escrever código preparado para um ambiente onde COBOL conversa diariamente com APIs, microsserviços, aplicações móveis e plataformas em nuvem.

Como Programador COBOL Padawan, seu objetivo não deve ser apenas aprender comandos. Deve ser entender por que eles existem, quando utilizá-los e como eles ajudam a construir sistemas capazes de sobreviver por décadas.

No Bellacosa Mainframe, costumamos dizer que a verdadeira modernização não começa com uma nova tecnologia. Ela começa quando o desenvolvedor muda sua forma de pensar. O compilador evolui, o hardware evolui, o IBM Z evolui — e o profissional que acompanha essa jornada deixa de apenas escrever programas para construir soluções que atravessam gerações.


terça-feira, 14 de abril de 2026

🧠 SMP/E na Prática: O que são MCS — Modification Control Statements?


Bellacosa Mainframe apresenta SMP/E na pratica o fluxo de um MCS



🧠 SMP/E na Prática : O que são MCS — Modification Control Statements?

Os MCS (Modification Control Statements) são instruções de controle usadas pelo SMP/E para descrever o que um pacote de manutenção contém e como ele deve ser instalado.

👉 Pense no MCS como a “receita” que diz ao SMP/E:

  • quais módulos vão ser substituídos,
  • quais macros entram ou saem,
  • dependências necessárias,
  • pré-requisitos,
  • co-requisitos,
  • SYSMODs substituídos,
  • módulos afetados,
  • e onde tudo deve ser aplicado.

Essas instruções aparecem normalmente dentro de:

  • PTFs (Program Temporary Fixes)
  • APARs
  • USERMODs
  • FMIDs (instalação de produtos)

🧾 Como os MCS são emitidos?

Você não digita MCS manualmente durante a aplicação normal. Eles vêm dentro dos pacotes de manutenção, distribuídos pelo fornecedor (ex.: IBM).

O fluxo típico é:

  1. Você recebe um PTF/APAR.
  2. Dentro dele existem blocos MCS, como:
    • ++VER
    • ++MOD
    • ++MAC
    • ++JCLIN
    • ++HOLD
    • ++IF / ++REQ / ++PRE
  3. Esses blocos descrevem ao SMP/E:
    • quais módulos substituir
    • como montar link-edit
    • dependências
    • regras de instalação

⚙️ Onde o APPLY entra nessa história?

O comando APPLY do SMP/E processa as instruções MCS e efetivamente instala as mudanças no ambiente target.

Fluxo simplificado:

  1. RECEIVE
    • lê os MCS e registra no banco SMP/E.
  2. APPLY
    • valida dependências declaradas nos MCS.
    • verifica PRE/REQ/IF.
    • monta JCL se houver ++JCLIN.
    • atualiza módulos, macros, etc.
  3. ACCEPT
    • confirma no DLIB (distribution library).

🔄 Relação direta entre MCS e APPLY

✔ Os MCS dizem o que fazer.
✔ O APPLY executa o que foi declarado.

Exemplo conceitual:

++VER
++MOD(MYMOD) DISTLIB(AOSL)
++MAC(MYMAC)
++JCLIN

O APPLY vai:

  • validar PREs e REQs,
  • aplicar módulos,
  • montar e executar o JCLIN,
  • atualizar o ambiente.

🧩 O APPLY “lê” os MCS?

Exatamente. O SMP/E usa os MCS como instruções de engenharia. O APPLY:

  • lê os blocos ++VER / ++MOD / ++MAC / ++JCLIN
  • monta a sequência correta
  • valida integridade
  • garante consistência entre FMIDs, SYSMODs e bibliotecas

Sem MCS, o APPLY não saberia o que fazer.


🧪 Exemplo didático

Imagine um PTF que corrige um módulo COBOL:

O MCS pode declarar:

++VER(Z038) FMID(HBB7780).
++MOD(IGYCRCTL) DISTLIB(SIGYLOAD).

O APPLY irá:

  • verificar FMID HBB7780
  • garantir dependências
  • substituir o módulo IGYCRCTL na loadlib correta

🧠 Resumo prático

  • MCS = linguagem que descreve a manutenção.
  • SMP/E = interpretador/engine.
  • APPLY = ação que materializa as mudanças.

Um exemplo de MCS realista para um PTF que altera componentes do IBM Enterprise COBOL for z/OS e depende do runtime do IBM Language Environment (LE).

⚠️ Este é um exemplo didático (estrutura fiel, mas nomes ilustrativos).


📦 Exemplo — MCS de um PTF de COBOL/LE

Imagine um PTF que:

  • Atualiza o módulo IGZCCTL (runtime LE para COBOL)
  • Atualiza o compilador IGYCRCTL
  • Exige um pré-requisito
  • Inclui JCLIN para link-edit

Exemplo MCS

++PTF(UX12345) REWORK(20260413).
++VER(Z038)
FMID(HIGY170)
PRE(UJ99999)
REQ(LE37000).

++HOLD(UX12345)
SYSTEM
REASON(ACTION)
DATE(260413)
COMMENT(
'Este PTF atualiza módulos do compilador COBOL e
componentes de runtime LE. Requer rebind após APPLY.'
).

++MOD(IGYCRCTL) DISTLIB(SIGYCOMP) SYSLIB(SIGYCOMP).
++MOD(IGZCCTL) DISTLIB(SCEERUN) SYSLIB(SCEERUN).

++MAC(IGZMAC01) DISTLIB(SCEEMAC).

++JCLIN.
//LKED EXEC PGM=IEWL,PARM='LIST,XREF,LET'
//SYSLMOD DD DSN=CEE.SCEERUN,DISP=SHR
//SYSLIN DD *
INCLUDE SYSLIB(IGZCCTL)
ENTRY IGZCCTL
NAME IGZCCTL(R)
/*
++END

🧠 O que cada bloco faz?

✔️ ++PTF

Define o SYSMOD e metadados.

✔️ ++VER

Define o FMID alvo (feature a ser mantida) e dependências:

  • PRE → pré-requisitos
  • REQ → requisitos obrigatórios

✔️ ++HOLD

Impede instalação automática e obriga ação manual (por exemplo, rebind).

✔️ ++MOD

Declara módulos a substituir e onde instalá-los.

✔️ ++MAC

Declara macros a atualizar.

✔️ ++JCLIN

Fornece instruções de link-edit que o SMP/E executará no APPLY.


⚙️ Como isso interage com APPLY?

Quando você executa:

SET BDY(TGT1).
APPLY PTFS(UX12345).

O SMP/E irá:

  1. Verificar FMID e PRE/REQ
  2. Validar HOLDS
  3. Copiar módulos declarados em ++MOD
  4. Rodar o JCLIN para link-edit
  5. Registrar o resultado no CSI

🧩 Resumo rápido

  • MCS = contrato do PTF
  • APPLY = motor que executa esse contrato
  • O ++JCLIN evita você montar manualmente link-edits 

sexta-feira, 20 de março de 2026

🚀 Do COPY ao CORE Bancário: A Jornada Jedi de um Programa COBOL no z/OS (ou: como um .CBL vira dinheiro no mundo real)

Bellacosa Mainframe apresenta COBOL LE Enterprise


🚀 Do COPY ao CORE Bancário: A Jornada Jedi de um Programa COBOL no z/OS (ou: como um .CBL vira dinheiro no mundo real)

“Padawan, muitos escrevem código. Poucos entendem como ele realmente vive.” 💙

Se você acha que COBOL é só um DISPLAY "HELLO", prepare-se.
No mainframe, um programa não nasce pronto — ele passa por uma verdadeira linha de produção industrial de software.

Hoje vamos percorrer essa jornada completa, estilo Bellacosa Mainframe™, com:

🔥 Passo a passo real
🧠 Conceitos que diferenciam dev júnior de arquiteto
💎 Easter eggs históricos
🏦 Exemplos do mundo bancário
⚙️ Bastidores que ninguém te conta


🧙‍♂️ Capítulo 1 — O nascimento: o código fonte

Tudo começa com um membro em um PDS ou PDSE:

USER.COBOL.SOURCE(PROG1)

Exemplo simples:

IDENTIFICATION DIVISION.
PROGRAM-ID. CPRIME.

PROCEDURE DIVISION.
DISPLAY "MAY THE MAINFRAME BE WITH YOU".
STOP RUN.

💡 Curiosidade Jedi:
COBOL foi criado para ser legível por pessoas de negócio. Por isso parece “verbal”.


📚 Capítulo 2 — COPY: os pergaminhos antigos

Nenhum sistema corporativo vive sem COPYBOOKS.

COPY CLIENT-RECORD.

Esses artefatos ficam nas bibliotecas apontadas por:

//SYSLIB DD DSN=CORP.COPYLIB

💎 Easter egg:
Grandes bancos têm copybooks mais antigos que muitos desenvolvedores.


⚙️ Capítulo 3 — Compilação: o forno industrial (IGYCRCTL)

Agora entra o compilador Enterprise COBOL.

//COMPILE EXEC PGM=IGYCRCTL

📥 Entradas principais

DDFunção
SYSINCódigo fonte
SYSLIBCopybooks
SYSUTxÁrea de trabalho

📤 Saídas

DDResultado
SYSPRINTMensagens
SYSLINObject code

👉 O objeto ainda NÃO é executável.


🧠 Analogia moderna

MainframeLinux
Compilegcc -c
Objeto.o

💥 Capítulo 4 — O Binder: alquimia digital (IEWL)

Agora o objeto vira programa executável.

//LKED EXEC PGM=IEWL

📥 Entrada

SYSLIN → objeto compilado

📤 Saída

SYSLMOD → executável final

💎 Easter egg:
Antes do Binder moderno, isso se chamava “link-edit”.


📦 Program Object: o formato moderno

Hoje o resultado normalmente é um:

👉 Program Object em PDSE

Não mais um load module antigo.


🧬 Capítulo 5 — O espírito invisível: Language Environment (LE)

Aqui está o segredo que separa aprendizes de mestres.

💥 Programas COBOL não rodam sozinhos.

Eles precisam do LE.

O LE fornece:

✔️ Memória
✔️ Inicialização
✔️ Tratamento de erros
✔️ Serviços runtime
✔️ Interoperabilidade


🧠 Analogia suprema

PlataformaRuntime
JavaJVM
.NETCLR
z/OS⭐ LE

⚙️ Capítulo 6 — Opções de runtime (CEEOPTS)

Exemplo famoso:

ALL31(ON)

Permite usar memória acima da linha de 16 MB.

🧪 Override via JCL

//CEEOPTS DD *
ALL31(ON)
/*

🚫 Nunca no código COBOL.


🏦 Capítulo 7 — Onde o programa pode rodar?

Um único executável pode viver em vários mundos:

AmbienteUso típico
BatchProcessamento massivo
CICSTransações online
IMSSistemas críticos
Db2 SPLógica no banco
TSOExecução interativa
USSScripts UNIX

❌ System exit — proibido (sem LE)


🐧 Capítulo 8 — USS e o mundo moderno

Você também pode compilar no UNIX do z/OS:

cob2 -q'RENT,LIST' pgm1.cbl

💡 O mainframe também fala “Linux”.


🧩 Capítulo 9 — Compatibilidade histórica (o verdadeiro poder)

Enterprise COBOL consegue recompilar código:

✔️ VS COBOL II (anos 80)
✔️ COBOL for OS/390

Mas não diretamente:

❌ OS/VS COBOL
❌ COBOL-68 / COBOL-74

💥 Isso é o que mantém sistemas funcionando por décadas.


🧙‍♂️ Capítulo 10 — A verdadeira força do mainframe

Um programa COBOL pode:

💥 Processar milhões de transações por segundo
💥 Rodar por décadas sem reescrita
💥 Integrar com APIs modernas
💥 Conviver com código de 40 anos atrás


🏆 Pipeline final — a jornada completa

Source (.CBL)

Compile (IGYCRCTL)

Object module

Binder (IEWL)

Program Object

Execution (Batch / CICS / IMS / etc.)

💎 Easter egg final

💰 Grande parte do dinheiro do planeta passa por sistemas exatamente assim.

Cada saque, compra com cartão ou transferência:

👉 Pode estar executando código COBOL semelhante ao seu.


🧠 Conclusão 

Padawan, aprender COBOL não é aprender uma linguagem.

É entender uma arquitetura de computação empresarial completa, refinada por mais de meio século.

🚀 O código é apenas o começo.
🏗️ O processo é o verdadeiro poder.
💙 O mainframe é a fábrica invisível do mundo moderno.



quinta-feira, 11 de maio de 2023

Guia Completo de COBOL Recursivo no IBM Mainframe

 

 

Bellacosa Mainframe cobol recursivo


☕ Um Café no Bellacosa Mainframe

Guia Completo de COBOL Recursivo no IBM Mainframe

Da Teoria à Engenharia de Software em Enterprise COBOL

Ao longo desta série exploramos um dos assuntos mais fascinantes — e também menos compreendidos — do Enterprise COBOL: a recursividade.

Embora poucos sistemas corporativos utilizem algoritmos recursivos no dia a dia, compreender esse recurso permite enxergar o funcionamento interno do Enterprise COBOL, do Language Environment (LE) e da pilha de execução (Call Stack), oferecendo uma visão muito mais profunda sobre como programas COBOL realmente funcionam.

Esta série foi escrita pensando no Programador COBOL Padawan que deseja evoluir para Pleno e Sênior, compreendendo não apenas a sintaxe da linguagem, mas também sua arquitetura e seus mecanismos internos. 

📘 Parte 1 — Conceitos Fundamentais

Nesta primeira parte mostramos que recursividade vai muito além do tradicional exemplo do cálculo do fatorial.

Foram apresentados conceitos como:

  • O que realmente significa um programa recursivo.

  • Como funciona o Call Stack.

  • Como o Enterprise COBOL cria novas ativações do programa.

  • Diferenças entre programas RECURSIVE e tradicionais.

  • A importância da Working-Storage e da Local-Storage.

  • Como o Language Environment participa da execução.

➡️ Leia a Parte 1: https://eljefemidnightlunch.blogspot.com/2023/01/cobol-recursivo-muito-alem-do-fatorial.html


📘 Parte 2A — Construindo o Primeiro Programa Recursivo

Na segunda etapa colocamos a teoria em prática.

Construímos um programa recursivo completo em Enterprise COBOL e acompanhamos sua execução passo a passo.

Entre os assuntos abordados:

  • Exemplo completo comentado.

  • Caso Base (Base Case).

  • Crescimento e redução da pilha.

  • Como ocorre o retorno das chamadas (Unwinding).

  • Comparação entre recursividade e PERFORM.

  • Boas práticas para evitar erros comuns.

➡️ Leia a Parte 2A:
https://eljefemidnightlunch.blogspot.com/2023/02/cobol-recursivo-muito-alem-do-fatorial.html


📘 Parte 2B — Aplicações Reais da Recursividade

Depois dos conceitos básicos, mostramos onde a recursividade realmente faz sentido em ambientes corporativos.

Foram apresentados diversos cenários reais, como:

  • Percorrimento de árvores.

  • Estruturas XML.

  • Objetos JSON.

  • Busca em profundidade (DFS).

  • QuickSort.

  • MergeSort.

  • Estruturas hierárquicas.

  • Organogramas.

  • Diretórios do z/OS UNIX (USS).

  • Conceitos utilizados por compiladores e bancos de dados.

Também discutimos quando não utilizar recursividade.

➡️ Leia a Parte 2B:
https://eljefemidnightlunch.blogspot.com/2023/03/cobol-recursivo-muito-alem-do-fatorial.html


📘 Parte 2C — Performance, Debugging e Engenharia

Na última parte entramos nos detalhes que normalmente interessam aos Programadores Mainframe mais experientes.

Entre os temas abordados:

  • Performance da recursividade.

  • Consumo de memória.

  • Stack Overflow.

  • Tail Recursion.

  • Call Stack.

  • Debugging de programas recursivos.

  • Análise de Dumps.

  • Papel do Language Environment (LE).

  • Working-Storage versus Local-Storage.

  • Checklist para utilização segura da recursividade.

  • Dicas, truques e curiosidades pouco conhecidas.

➡️ Leia a Parte 2C:

https://eljefemidnightlunch.blogspot.com/2023/04/cobol-recursivo-muito-alem-do-fatorial.html


O que um Programador COBOL deve levar desta série?

Mesmo que você nunca desenvolva um algoritmo recursivo em produção, compreender esse tema permitirá entender melhor:

  • Como o Enterprise COBOL administra memória.

  • Como funciona a pilha de chamadas.

  • Como parâmetros são preservados.

  • O papel do Language Environment.

  • Por que existe a Local-Storage Section.

  • Como analisar dumps mais complexos.

  • Como modelar problemas hierárquicos de forma elegante.

Em outras palavras, estudar recursividade não serve apenas para aprender uma técnica de programação; serve para compreender a engenharia invisível que sustenta aplicações críticas executadas diariamente no IBM Z.

Conclusão

Recursividade é uma ferramenta poderosa, mas não deve ser utilizada apenas porque produz código elegante. Em processamento linear, o tradicional PERFORM continua sendo, na maioria dos casos, a solução mais eficiente.

Entretanto, quando lidamos com árvores, estruturas aninhadas, documentos XML, objetos JSON, algoritmos de busca, compiladores e diversos outros problemas naturalmente hierárquicos, a recursividade oferece uma forma clara, organizada e expressiva de modelar a solução.

Esperamos que esta série tenha ajudado você a enxergar o Enterprise COBOL sob uma nova perspectiva. Mais do que aprender um recurso da linguagem, você percorreu uma jornada pela arquitetura do IBM Mainframe, compreendendo como memória, pilha de execução, Language Environment e engenharia de software trabalham em conjunto para manter alguns dos sistemas mais críticos do mundo em funcionamento.

☕ Nos encontramos no próximo Café no Bellacosa Mainframe!


quarta-feira, 19 de abril de 2023

COBOL Recursivo — Muito Além do Fatorial (Parte II section C)

 

Bellacosa Mainframe apresenta cobol recursivo parte II sec c

☕ Um Café no Bellacosa Mainframe

COBOL Recursivo — Muito Além do Fatorial (Parte 2C)

Performance, Tail Recursion, Debugging, Language Environment e os Segredos que Todo Programador Mainframe Deveria Conhecer

"A pergunta que todo Programador COBOL Sênior faz não é 'a recursão funciona?', mas sim 'quanto ela custa, quando vale a pena e como o Enterprise COBOL administra tudo isso por baixo dos panos?'" 


Introdução

Chegamos à última parte da nossa jornada.

Na Parte 1 entendemos o conceito.

Na Parte 2A acompanhamos a pilha crescendo e diminuindo.

Na Parte 2B vimos onde a recursividade realmente faz sentido.

Agora vamos responder às perguntas que normalmente aparecem em entrevistas técnicas e discussões entre Programadores Sêniores.

  • A recursão é lenta?

  • Quanto de memória ela consome?

  • O compilador otimiza chamadas recursivas?

  • Existe Tail Recursion no Enterprise COBOL?

  • Como depurar uma rotina recursiva?

  • O que acontece em um dump?

  • Como o Language Environment administra tudo isso?

Prepare mais um café.

Agora vamos olhar por dentro do motor do Enterprise COBOL.


O verdadeiro custo de uma chamada recursiva

Imagine uma rotina extremamente simples.

ROTINA A

↓

ROTINA A

↓

ROTINA A

↓

ROTINA A

Muitos imaginam que apenas uma instrução CALL é executada.

Na realidade ocorre muito mais.

Cada chamada exige que o sistema preserve o contexto da execução atual antes de iniciar a próxima.

Normalmente isso envolve:

  • salvar registradores utilizados;

  • armazenar o endereço de retorno;

  • reservar espaço para variáveis locais;

  • preparar parâmetros;

  • criar um novo frame de execução;

  • transferir o controle para a nova ativação.

Quando essa rotina retorna, todo esse processo acontece novamente, porém na ordem inversa.


Quanto custa isso?

Cada chamada possui um custo fixo.

Imagine uma recursão com profundidade 500.

Teremos aproximadamente:

  • 500 ativações;

  • 500 retornos;

  • centenas de registradores preservados;

  • centenas de frames criados.

Enquanto isso um simples:

PERFORM VARYING

reutiliza praticamente o mesmo ambiente durante toda a execução.

É por isso que loops costumam ser mais rápidos.


O PERFORM continua sendo o campeão

Imagine um processamento de um arquivo VSAM.

100 milhões de registros

Qual solução utilizar?

Recursão?

Jamais.

O correto continua sendo.

PERFORM UNTIL EOF

Por quê?

Porque o problema é linear.

Cada registro é independente.

Não existe árvore.

Não existe hierarquia.

Não existe motivo para criar milhares de novos contextos de execução.


Quando a recursão vence

Agora imagine.

Empresa

↓

Departamento

↓

Subdepartamento

↓

Equipe

↓

Funcionário

Aqui o problema possui profundidade variável.

Não sabemos quantos níveis existirão.

A estrutura muda constantemente.

Nesse cenário a recursividade pode produzir um código muito menor, mais legível e muito mais fácil de manter.


Complexidade não é desempenho

Existe uma confusão bastante comum.

Alguns desenvolvedores acreditam que:

"Se um algoritmo é recursivo então ele é lento."

Não.

O que determina o desempenho é o algoritmo.

QuickSort continua sendo extremamente eficiente.

MergeSort também.

DFS também.

A recursão é apenas uma técnica utilizada para implementar esses algoritmos.


A profundidade da pilha

Imagine.

Nível 1

↓

Nível 2

↓

Nível 3

↓

...

↓

Nível 500

Cada nível ocupa memória.

Quanto maior a profundidade.

Maior o consumo.

Por isso uma pergunta importante é:

Qual a profundidade máxima esperada?


Stack Overflow

Toda pilha possui limite.

Se o algoritmo continuar chamando a si próprio indefinidamente.

Chegará um momento em que não haverá espaço suficiente.

Resultado.

Stack Overflow.

Em ambientes Enterprise COBOL isso normalmente se manifesta como falha de execução provocada pelo esgotamento da pilha ou da região disponível para o processo.


Como evitar?

Existem algumas regras simples.

Sempre possuir:

  • caso base;

  • redução do problema;

  • validação da entrada;

  • profundidade conhecida.

Nunca confiar que os dados "sempre estarão corretos".


Um pequeno erro pode ser catastrófico

Imagine.

PROCESSA(100)

↓

PROCESSA(100)

↓

PROCESSA(100)

Percebe o problema?

O valor nunca muda.

O caso base jamais será alcançado.

O algoritmo continuará chamando a si próprio até consumir toda a pilha.

Esse é um dos bugs mais perigosos em programas recursivos.


Tail Recursion

Agora chegamos a um assunto que raramente aparece em livros de COBOL.

Considere.

ROTINA

↓

chama novamente

↓

retorna imediatamente

Não existe mais nada para fazer após o retorno.

Esse padrão recebe o nome de Tail Recursion.


Por que ela é especial?

Alguns compiladores conseguem transformar automaticamente esse tipo de recursão em um simples loop.

Resultado.

A pilha praticamente deixa de crescer.

Essa otimização é conhecida como Tail Call Optimization (TCO).


E o Enterprise COBOL?

O Enterprise COBOL não é conhecido por realizar uma otimização geral de Tail Call equivalente à encontrada em linguagens como Scheme ou algumas implementações modernas de C/C++. Em outras palavras, não é seguro assumir que uma chamada recursiva em posição de cauda será convertida automaticamente em um laço.

A recomendação prática para aplicações corporativas continua sendo:

  • se a profundidade pode ser grande;

  • e existe uma solução iterativa clara;

prefira PERFORM.

Sempre que escrever uma rotina recursiva pensando em desempenho, consulte a documentação da versão específica do compilador e valide o comportamento com testes e medições.


Debugging

Aqui começa uma das maiores dificuldades.

Imagine um breakpoint.

Você observa.

LS-NUMERO = 4

Continua executando.

Agora.

LS-NUMERO = 3

Depois.

LS-NUMERO = 2

Depois.

LS-NUMERO = 1

O iniciante acredita que a variável está sendo alterada.

Na realidade.

Você está olhando ativações diferentes.

Cada uma possui sua própria Local-Storage.

Esse detalhe costuma confundir quem está depurando um programa recursivo pela primeira vez.


Como depurar corretamente

A primeira dica.

Sempre descubra:

"Em qual nível da pilha estou?"

Depois.

Observe:

  • parâmetros;

  • variáveis locais;

  • valor de retorno.

Nunca apenas o conteúdo de uma variável.


O Dump

Quando ocorre um abend.

O dump costuma revelar algo parecido.

ROTINA

↓

ROTINA

↓

ROTINA

↓

ROTINA

↓

ROTINA

Centenas de vezes.

Isso normalmente indica:

  • ausência de caso base;

  • dados inválidos;

  • profundidade inesperada.

Aprender a reconhecer esse padrão economiza muitas horas de investigação.


Language Environment (LE)

Poucos Programadores Júnior conhecem o LE.

Mas praticamente todo programa Enterprise COBOL moderno depende dele.

O Language Environment é responsável por diversos serviços de tempo de execução, incluindo a organização do ambiente necessário para chamadas de programas, tratamento de exceções, gerenciamento de pilha e integração entre linguagens.

Quando um programa recursivo cria novas ativações, existe uma infraestrutura por trás garantindo que cada contexto seja preservado corretamente.

Sem esse ambiente de execução seria muito mais difícil oferecer suporte consistente a recursos modernos do Enterprise COBOL.


O papel do LOCAL-STORAGE revisitado

Depois de tudo que vimos.

Fica fácil entender.

Cada frame precisa de suas próprias variáveis.

É exatamente isso que Local-Storage oferece.

Visualmente.

+-------------------+

Frame 1

LOCAL-STORAGE

+-------------------+

Frame 2

LOCAL-STORAGE

+-------------------+

Frame 3

LOCAL-STORAGE

+-------------------+

Cada chamada possui sua própria área.

Nenhuma interfere na outra.


E a Working-Storage?

Continua existindo.

Mas pertence ao programa.

Não à chamada.

Visualmente.

WORKING-STORAGE

↓

Frame 1

↓

Frame 2

↓

Frame 3

Todos enxergam a mesma área.

Por isso ela deve armazenar apenas informações realmente compartilhadas.


O impacto em aplicações CICS

Embora o CICS suporte programas escritos em Enterprise COBOL, nem todo programa é um bom candidato à recursão.

Em aplicações OLTP, normalmente buscamos:

  • baixa latência;

  • previsibilidade;

  • consumo controlado de recursos.

Por isso, algoritmos profundamente recursivos raramente aparecem na lógica de transações de alta frequência.

Quando uma solução recursiva for necessária, ela deve ser cuidadosamente analisada quanto à profundidade máxima, uso de memória e comportamento sob carga.


Recursão e paralelismo

Existe outro ponto interessante.

Recursividade não significa paralelismo.

Nem concorrência.

São conceitos completamente diferentes.

É possível possuir:

  • algoritmo recursivo sequencial;

  • algoritmo iterativo paralelo;

  • algoritmo recursivo paralelo.

Não confunda os conceitos.


Quando um Sênior escolhe recursão?

Normalmente quando observa:

✓ estrutura hierárquica

✓ profundidade variável

✓ código muito mais simples

✓ facilidade de manutenção

✓ menor complexidade lógica

Ou seja.

A decisão raramente é baseada apenas em velocidade.


Checklist Bellacosa ☕

Antes de escrever um algoritmo recursivo, faça estas perguntas:

  • Existe um caso base claramente definido?

  • Cada chamada aproxima o problema desse caso base?

  • A profundidade máxima é conhecida ou razoavelmente limitada?

  • Uma solução iterativa seria significativamente mais simples?

  • As variáveis específicas de cada chamada estão em LOCAL-STORAGE?

  • O algoritmo foi testado com entradas extremas?

  • O comportamento em erro e em dumps é compreendido pela equipe?

Se alguma resposta for "não", vale a pena revisar o projeto antes de seguir.


Truques de Programador Mainframe

Algumas boas práticas que ajudam muito.

✔ Nunca misture lógica recursiva com variáveis globais desnecessárias.

✔ Documente claramente qual é o caso base.

✔ Comente qual parâmetro reduz o problema.

✔ Sempre teste entradas:

  • mínimas;

  • máximas;

  • inválidas.

✔ Desenhe a árvore de chamadas antes de codificar.

✔ Não escolha recursão apenas porque o código fica "bonito".

Código elegante que produz um abend continua sendo um programa ruim.


Easter Egg Bellacosa ☕

Existe uma curiosidade interessante.

Muitos Programadores Mainframe trabalham vinte ou trinta anos sem escrever um único algoritmo recursivo.

Mesmo assim.

Os melhores profissionais costumam compreender perfeitamente:

  • Call Stack;

  • Frames;

  • Local-Storage;

  • Language Environment;

  • Endereços de retorno;

  • Passagem de parâmetros.

Por quê?

Porque todos esses conceitos aparecem diariamente em dumps, depuração, integração com C, Assembler, APIs, LE e análise de problemas complexos.

Ou seja.

Você pode nunca escrever um QuickSort recursivo.

Mas provavelmente utilizará o conhecimento adquirido estudando recursão durante toda sua carreira.


Uma reflexão final

Existe um velho ditado entre arquitetos de software.

"Toda abstração tem um custo."

A recursividade é uma abstração poderosa.

Ela reduz dezenas de linhas de código para poucas chamadas elegantes.

Em troca.

Consome pilha.

Cria novos contextos.

Exige planejamento.

O Programador Júnior pergunta:

"Posso usar?"

O Programador Pleno pergunta:

"Vale a pena usar?"

O Programador Sênior pergunta:

"Qual é o impacto dessa decisão daqui a cinco anos?"

É essa mudança de perspectiva que diferencia quem apenas domina a sintaxe de quem realmente compreende engenharia de software.


Conclusão da Série

Se você acompanhou esta série desde a Parte 1, provavelmente percebeu que o objetivo nunca foi ensinar apenas um algoritmo de fatorial.

Nosso verdadeiro objetivo foi mostrar que a recursividade é uma porta de entrada para compreender a arquitetura do Enterprise COBOL.

Ao estudar esse tema, aprendemos sobre:

  • Call Stack;

  • Frames de execução;

  • RECURSIVE;

  • WORKING-STORAGE versus LOCAL-STORAGE;

  • passagem de parâmetros;

  • modelagem de problemas hierárquicos;

  • árvores, XML, JSON e algoritmos clássicos;

  • desempenho, consumo de memória e depuração.

Talvez você passe toda a carreira sem precisar implementar uma rotina recursiva em produção.

Ainda assim, entender como ela funciona tornará muito mais fácil compreender dumps, o Language Environment, integrações com C e Assembler, além do comportamento interno do Enterprise COBOL.

No fim das contas, a maior contribuição da recursividade não é ensinar o computador a chamar uma rotina novamente.

É ensinar o programador a pensar em estruturas, contexto, memória e arquitetura.

E essa forma de pensar acompanha um verdadeiro Engenheiro Mainframe por toda a vida profissional.

☕ Fim da série "COBOL Recursivo — Muito Além do Fatorial". Juntas, as Partes 1, 2A, 2B e 2C formam um material extenso e progressivo, saindo dos fundamentos até aspectos de arquitetura e engenharia de software voltados ao Enterprise COBOL no IBM Z.


sexta-feira, 31 de março de 2023

COBOL Recursivo — Muito Além do Fatorial (Parte II Section B)


 

Bellacosa Mainframe apresenta cobol recursivo parte II sec b

☕ Um Café no Bellacosa Mainframe

COBOL Recursivo — Muito Além do Fatorial (Parte 2B)

Quando a Recursividade Deixa de Ser Exercício e Passa a Resolver Problemas Reais no IBM Mainframe

"Depois que um programador entende o Call Stack, surge uma pergunta inevitável: se a recursão é mais lenta que um PERFORM, por que compiladores, bancos de dados, processadores XML e até o próprio z/OS utilizam algoritmos recursivos? A resposta está no tipo de problema que estamos tentando resolver."


Introdução

Na Parte 2A utilizamos o exemplo do fatorial.

Foi uma excelente ferramenta didática.

Mas sejamos honestos.

Você dificilmente encontrará um sistema bancário calculando fatoriais durante o fechamento do dia.

Da mesma forma, poucas empresas utilizam Fibonacci em produção.

Esses algoritmos são importantes porque ensinam os fundamentos.

Entretanto, a verdadeira força da recursividade aparece quando o problema deixa de ser linear.

É exatamente aí que muitos programadores COBOL começam a enxergar a diferença entre escrever código e modelar problemas.

Hoje vamos abandonar os exemplos acadêmicos e explorar situações que realmente aparecem em software corporativo.


O primeiro sinal de que um problema pode ser recursivo

Existe uma pergunta simples.

"O objeto que estou processando pode conter outro objeto igual a ele?"

Se a resposta for sim...

Existe uma grande chance de a recursividade ser uma excelente solução.

Observe.

Uma pasta contém...

Pastas.

Um departamento possui...

Subdepartamentos.

Um XML contém...

Outros elementos XML.

Um menu possui...

Submenus.

Uma árvore possui...

Galhos.

Cada galho possui...

Outros galhos.

O próprio problema descreve sua solução.


Fibonacci: o exemplo que ensina e também alerta

Depois do fatorial, Fibonacci é provavelmente o algoritmo recursivo mais famoso.

F(0)=0

F(1)=1

F(2)=1

F(3)=2

F(4)=3

F(5)=5

F(6)=8

Sua definição é extremamente elegante.

F(N)=F(N-1)+F(N-2)

Visualmente.

               F(6)

          /            \

      F(5)            F(4)

     /    \          /    \

 F(4)    F(3)    F(3)    F(2)

Perceba algo importante.

A mesma conta aparece diversas vezes.

F(4).

F(3).

F(2).

Tudo é recalculado.


O lado sombrio da recursividade

Embora o algoritmo seja bonito...

Ele é extremamente ineficiente.

Imagine calcular:

F(50)

Milhares de chamadas serão repetidas.

A árvore cresce exponencialmente.

É um excelente exemplo de como uma solução elegante pode se tornar um desastre de desempenho.

É por isso que muitos algoritmos recursivos modernos utilizam Memoization (armazenar resultados já calculados) ou são convertidos em versões iterativas quando desempenho extremo é necessário.

Essa é uma lição importante para qualquer Padawan: nem toda recursão elegante é uma boa solução para produção.


Árvores: onde a recursividade realmente brilha

Imagine o organograma de uma empresa.

                Presidente

        /          |           \

 Financeiro       RH          Tecnologia

                 /   \

           Folha     Recrutamento

Cada departamento pode possuir outros departamentos.

Cada um deles pode possuir outros.

Não existe um limite fixo.

Como percorrer isso?


Solução utilizando PERFORM

É possível.

Mas rapidamente surgem:

  • tabelas auxiliares;

  • índices;

  • controle de profundidade;

  • pilhas artificiais;

  • lógica de retorno.

O código cresce.

A manutenção se torna complicada.


Solução recursiva

A lógica passa a ser quase uma descrição em português.

Processe este departamento.

Para cada filho

    processe o filho.

Observe.

A estrutura do algoritmo é praticamente igual à estrutura da árvore.

Esse é o verdadeiro poder da recursividade.


XML: um dos melhores exemplos no Mainframe

Hoje praticamente todo ambiente IBM Z conversa com XML.

Imagine.

<empresa>

   <departamento>

      <funcionario>

         <dependente/>

      </funcionario>

   </departamento>

</empresa>

Cada elemento pode conter outros elementos.

Que podem conter outros elementos.

Que podem conter outros elementos.

Até centenas de níveis.

Como percorrer isso?

Recursivamente.


Visualmente.

Empresa

↓

Departamento

↓

Funcionário

↓

Dependente

Cada elemento executa exatamente o mesmo algoritmo.

"Procure meus filhos."

Se encontrar.

Execute novamente.


JSON segue exatamente a mesma ideia

Imagine.

{
   "cliente":
   {
      "endereco":
      {
         "cidade":
         {
            "bairro":"..."
         }
      }
   }
}

Cada objeto contém outro objeto.

Cada objeto utiliza exatamente a mesma lógica.

É uma árvore.

E árvores gostam de recursão.


O XML PARSER do Enterprise COBOL

Poucos desenvolvedores sabem disso.

Quando utilizamos o recurso XML PARSE do Enterprise COBOL, internamente existe um processamento altamente estruturado para percorrer nós, atributos e elementos aninhados.

Embora a implementação interna da IBM utilize diversas otimizações, o conceito fundamental continua sendo o de navegar por uma estrutura hierárquica.

Esse é um excelente exemplo de como compreender recursividade ajuda a entender tecnologias que usamos diariamente, mesmo sem escrever chamadas recursivas explicitamente.


Sistemas de menus

Imagine um sistema.

Cadastros

↓

Clientes

↓

Endereços

↓

Histórico

Outro menu.

Financeiro

↓

Pagamentos

↓

Boletos

Tudo isso pode ser representado por árvores.

A rotina que desenha um menu pode chamar a si própria sempre que encontrar um submenu.


Diretórios do z/OS UNIX

Embora muitos profissionais associem Mainframe apenas a datasets, o z/OS possui um ambiente UNIX extremamente robusto.

Imagine.

/

├── u

│     ├── vagner

│     ├── projetos

│     └── scripts

└── tmp

Uma rotina que lista diretórios faz exatamente isto.

Entre.

Liste arquivos.

Encontrou pasta?

Entre novamente.

Esse algoritmo praticamente escreve sozinho utilizando recursividade.


Busca em Profundidade (DFS)

Um dos algoritmos mais importantes da Computação.

Depth First Search.

Visualmente.

          A

      /      \

     B        C

   /   \       \

  D     E       F

A busca acontece assim.

A

↓

B

↓

D

↑

B

↓

E

↑

A

↓

C

↓

F

Observe.

Sempre mergulhamos o máximo possível.

Depois retornamos.

Depois continuamos.

Isso acontece naturalmente utilizando recursão.


Busca em Largura (BFS)

Já a Breadth First Search prefere percorrer nível por nível.

Ela normalmente utiliza filas.

Não recursão.

Esse é um ótimo exemplo de que nem todo algoritmo sobre árvores precisa ser recursivo.

O desenvolvedor deve escolher a ferramenta adequada ao problema.


QuickSort

Outro algoritmo clássico.

Imagine.

15

↓

Escolha pivô

↓

Menores

Maiores

↓

Repita para cada lado

Cada metade repete exatamente o mesmo algoritmo.

Recursivamente.


MergeSort

Visualmente.

64 15 10 5

↓

64 15

10 5

↓

64

15

10

5

Quando cada pedaço está ordenado.

Eles são reunidos novamente.

O algoritmo divide.

Depois conquista.

Exatamente como o fatorial.


Divide and Conquer

Existe uma família inteira de algoritmos baseada nesse princípio.

  1. Dividir o problema.

  2. Resolver problemas menores.

  3. Unir os resultados.

Sempre que enxergamos esse padrão, vale a pena perguntar:

"A recursividade simplifica esta solução?"


Árvore B e índices de banco de dados

Db2.

IMS.

VSAM.

Sistemas de arquivos.

Todos utilizam árvores internamente.

Imagine procurar um registro.

Você começa na raiz.

Depois escolhe um galho.

Depois outro.

Depois outro.

Até encontrar a folha.

Embora o código interno dos produtos IBM seja altamente otimizado e frequentemente utilize abordagens iterativas para reduzir consumo de pilha, a lógica conceitual é equivalente ao caminhamento recursivo de uma árvore.


Compiladores

Pouca gente imagina.

Mas compiladores adoram recursão.

Imagine.

A+B*C

Transforma-se em.

          +

      /       \

     A         *

            /     \

           B       C

Cada nó da árvore representa uma operação.

O compilador percorre.

Depois gera código.

Esse processo é conhecido como navegação por uma Árvore Sintática Abstrata (AST).

Mesmo quando a implementação final utiliza otimizações sofisticadas, pensar recursivamente torna a construção dessas estruturas muito mais natural.


Interpretadores

Motores de regras.

Interpretadores.

Calculadoras.

Expressões matemáticas.

Todos trabalham sobre árvores.

Por isso a recursão aparece com frequência.


Onde isso aparece no IBM Z?

Mais do que muitos imaginam.

Alguns exemplos.

  • Processamento XML.

  • Navegação JSON.

  • Ferramentas de análise sintática.

  • Produtos que interpretam linguagens.

  • Utilitários de transformação de documentos.

  • Ferramentas de administração de diretórios USS.

  • Alguns componentes de compiladores e analisadores.

Mesmo que você nunca implemente esses produtos, entender como eles funcionam amplia sua capacidade de projetar soluções.


Um erro muito comum

Depois de aprender recursão.

Alguns desenvolvedores tentam utilizá-la em tudo.

Por exemplo.

Ler arquivo VSAM

↓

Processar registro

↓

Chamar novamente

Não.

Esse é um processamento linear.

O correto continua sendo.

PERFORM UNTIL EOF

Recursão aqui apenas aumenta:

  • consumo de memória;

  • número de chamadas;

  • profundidade da pilha;

  • tempo de execução.

Sem qualquer benefício.


Um teste simples

Antes de decidir.

Pergunte.

Meu problema é:

  • Linear?

ou

  • Hierárquico?

Se for linear.

Use PERFORM.

Se for uma estrutura em árvore.

A recursão provavelmente merece consideração.


A maior lição desta parte

A recursividade não existe para substituir laços.

Ela existe para modelar problemas cuja própria natureza é recursiva.

Quando a estrutura do problema se repete dentro dela mesma, a solução recursiva tende a ser mais elegante, mais legível e mais próxima da forma como pensamos o domínio do problema.

É por isso que ela continua relevante, mesmo em uma linguagem tradicionalmente associada ao processamento sequencial como o COBOL.


Easter Egg Bellacosa ☕

Existe uma curiosidade interessante que raramente aparece em cursos de COBOL.

Quando um programador aprende recursão, normalmente acredita que o objetivo é escrever programas que chamam a si mesmos.

Na prática, o maior ganho costuma ser outro.

Depois de estudar recursividade, muitos desenvolvedores passam a compreender muito melhor:

  • por que existe LOCAL-STORAGE;

  • como funciona o CALL BY REFERENCE;

  • por que o Language Environment (LE) precisa administrar uma pilha de execução;

  • como compiladores preservam contexto entre chamadas;

  • por que produtos como Db2, CICS, XML PARSER e diversos componentes do z/OS conseguem processar estruturas complexas de forma organizada.

Curiosamente, alguns dos programadores COBOL mais experientes que você encontrará talvez nunca tenham escrito uma rotina recursiva em produção. Ainda assim, eles entendem profundamente o conceito porque sabem que recursão é uma ferramenta para compreender arquitetura, não apenas um estilo de programação.


Encerrando o Café

Se o fatorial nos ensinou como uma chamada recursiva nasce e morre, os exemplos desta parte mostram por que essa técnica continua viva mais de sessenta anos depois do surgimento do COBOL.

Árvores, XML, JSON, compiladores, algoritmos de busca e estruturas hierárquicas compartilham uma característica em comum: todos descrevem problemas que contêm versões menores de si mesmos.

É exatamente nesses cenários que a recursividade deixa de ser um exercício de faculdade e passa a ser uma poderosa ferramenta de modelagem.

No próximo café, vamos olhar para a recursão sob a ótica de um Programador Mainframe Sênior. Analisaremos desempenho, consumo de memória, profundidade de pilha, Tail Recursion, otimizações do compilador, depuração, análise de dumps, interação com o Language Environment e diversas dicas práticas para decidir, com segurança, quando usar — e principalmente quando evitar — a recursividade em aplicações Enterprise COBOL.

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