O famigerado comando ALTER

Poucos comandos podem ser tão contrários às boas práticas de programação em COBOL quanto o comando ALTER. Mas entender como ele funciona, o que ele se propõe a fazer e quais são os efeitos a longo prazo podem nos ajudar a pensar melhor em nossos programas, antes de começar a codifica-los.

A origem

O comando ALTER existe desde a primeira versão do COBOL, criada em 1959 pelo CODASYL, e continuou existindo em todas as revisões da ANSI até 2002, quando foi definitivamente eliminado.

Seu objetivo era permitir que um programa fosse “automodificável”. E essa expressão, por si só, já dá uma ideia dos efeitos nefastos que ele pode provocar na facilidade de manutenções futuras.

Como funciona

O comando ALTER permite que, em tempo de execução, um comando GO TO seja modificado para desviar para um outro parágrafo, que não aquele que foi originalmente codificado pelo programador. Sua sintaxe é:

ALTER (parágrafo1) TO PROCEED TO (parágrafo2)

O trecho abaixo mostra o que seria um exemplo hipotético:

DESVIO.

    GO TO CONTINUA-1.

CONTINUA-1.

    MOVE A TO B
    ADD C TO D
    ...
    ...

    GO TO CONTINUA-3.

CONTINUA-2.

    MOVE E TO F
    ADD G TO H
    ...
    ...

CONTINUA-3.

    WRITE REGISTRO FROM DETALHE.
    ADD 1 TO REG-LIDOS
    ...
    ...

MAIS-ADIANTE.

    ALTER DESVIO TO PROCEED TO CONTINUA-2.

No exemplo acima, o parágrafo DESVIO foi originalmente codificado para desviar para o parágrafo CONTINUA-1. Em um ponto mais adiante do programa, porém, o programador codificou a instrução ALTER para que, a partir desse momento, ao invés de desviar para CONTINUA-1 o parágrafo DESVIO passasse a desviar para CONTINUA-2. E assim o programa fará até que um novo comando ALTER altere essa situação.

Uma exigência da sintaxe do ALTER é que o GO TO seja o único comando do parágrafo afetado (no nosso exemplo, o parágrafo chamado DESVIO).

Repare que, usando esse recurso, nosso programador hipotético prejudicou bastante a vida do/da miserável colega que, no futuro, terá que entender e corrigir um problema de madrugada. Sozinho. Com sono. Com fome. Com o ar condicionado travado nos 10 graus. Vestindo camiseta.

Nosso desafortunado colega de profissão vê um parágrafo dizendo que o programa desvia para CONTINUA-1, mas em tempo de execução ele poderá desviar para CONTINUA-2. E se o parágrafo MAIS-ADIANTE estiver realmente “muito mais adiante”, ele vai demorar para entender o que está acontecendo.

Um exemplo real com o ALTER

Mais difícil do que explicar o comando ALTER é encontrar, aqui no século XXI, um exemplo real que justifique o uso desse comando. Eu mesmo, em 30 anos, só vi o ALTER “ao vivo” em dois programas, que naturalmente eu tive que reescrever.

Para imaginar o que seria um uso “justificável” para o ALTER precisamos voltar no tempo e pensar com a cabeça daqueles que sofriam para encaixar seus programas em alguns poucos kilobytes de memória real, com capacidade limitada de processamento.

Um IF hoje é banal, utilizado sem cerimônia por qualquer programador, em qualquer linguagem. Mas ele pode gerar uma grande quantidade de instruções de máquina. Numa época em que os ciclos do processador eram lentos, economizar IFs podia fazer a diferença entre uma performance razoável e uma performance inaceitável. Na mesma linha, codificar um programa de forma modular ou estruturada geraria mais instruções de máquina. O programa tinha que ser linear, curto e direto.

Nosso programador ancestral poderia usar o ALTER, portanto, para evitar que seu programa executasse múltiplos IFs ou múltiplos PERFORMs. Um programa, por exemplo, que processasse vários tipos de arquivo, mas que não pudesse testar, registro a registro, o tipo de arquivo recebido.

Foi pensando assim que imaginei o trecho de código abaixo:

PROCEDURE DIVISION.
INICIO.

    ACCEPT PARAMETRO FROM SYSIN
    IF PARAMETRO-TIPO-ARQUIVO = “1”
       ALTER PROCESSAMENTO TO PROCEED TO PROCESSA-ARQUIVO-1
    ELSE
       ALTER PROCESSAMENTO TO PROCEED TO PROCESSA-ARQUIVO-2
    END-IF

    OPEN INPUT ARQUIVO-ENTRADA
    OPEN I-O ARQUIVO-SAIDA.

LE-ARQUIVO-ENTRADA.

    READ ARQUIVO-ENTRADA AT END GO TO FINALIZA.
    MOVE ARQUIVO-ENTRADA-CHAVE TO ARQUIVO-SAIDA-CHAVE.

    READ ARQUIVO-SAIDA INVALID KEY GO TO LE-ARQUIVO-ENTRADA.

PROCESSAMENTO.

    GO TO PROCESSA-ARQUIVO-1.

PROCESSA-ARQUIVO-1.

    ADD ARQUIVO-ENTRADA-VALOR TO ARQUIVO-SAIDA-VALOR
    REWRITE REGISTRO-SAIDA
    GO TO LE-ARQUIVO-ENTRADA.

PROCESSA-ARQUIVO-2.

    SUBTRACT ARQUIVO-ENTRADA-VALOR FROM ARQUIVO-SAIDA-VALOR
    REWRITE REGISTRO-SAIDA
    GO TO LE-ARQUIVO-ENTRADA.

FINALIZA.

    CLOSE ARQUIVO-ENTRADA ARQUIVO-SAIDA.
    STOP RUN.

No exemplo acima, o programa pode processar dois tipos de arquivos: 1 ou 2. O tipo de arquivo é informado por um parâmetro configurado num cartão SYSIN, recebido no início da PROCEDURE DIVISION.

Se o programa estiver processando um arquivo do tipo 1, os valores existentes no arquivo deverão ser somados a um registro do arquivo de saída. Se for do tipo 2, os valores deverão ser subtraídos desse mesmo registro do arquivo de saída.

Repare que, nesse caso, nosso programador pré-cambriano preferiu executar um único comando ALTER no início do programa a ter que executar vários IFs e/ou PERFORMs em função do tipo de arquivo recebido.

Conclusão

O que a análise sobre o comando ALTER nos proporciona é uma reflexão sobre o que realmente significam as boas práticas de programação, hoje em dia. Num cenário onde as restrições de memória e ciclos de processamento não são tão leoninas quanto em tempos anteriores, a preocupação excessiva com performance pode prejudicar (e muito) a manutenção do programa no futuro.

E tudo o que queremos é que nosso colega do futuro – com fome, sono e frio – faça seu trabalho da melhor forma possível.

Publicado por

P.A.Dias

Paulo André tem mais de 30 anos de experiência em desenvolvimento e manutenção de sistemas em plataforma mainframe. Atuou como programador, analista, coordenador técnico, gerente e executivo de projetos em uma multinacional da área de Tecnologia da Informação.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *