Cadastro de Clientes em COBOL – CRUD

Apesar de eu achar que a versão estável do gnu COBOL necessite diversas melhorias que veremos no decorrer do artigo, não impede a sua utilização para aplicações diversas. Resolvi fazer um programinha CRUD (Create, Read, Update, Delete) para cadastrar clientes. A ideia veio depois de ligar para uma empresa que entrega água e eles pedirem o endereço mesmo já tendo comprada deles. É só a empresa ter um cadastro, pedir o telefone, informar ao programa e confirmar o endereço. É um programa simples e foi feito mais para mostrar algumas características da linguagem do que para mostrar boas técnicas de programação.

Abaixo, podemos ver o programa sendo executado, mostrando as opções de inclusão, consulta, alteração e exclusão de registros de clientes.

O fonte do programa encontra-se no github. Para baixar, você pode usar o botão Download zip ou no botão raw e salvar como clientes.cob. Para acompanhar as explicações abaixo, é interessante que você abra o link acima em outra janela ou aba. Não vou colocar o número de linha nas explicações pois existe a possibilidade de alterações e teria que adequar o artigo. Também é interessante pois obriga você a ler o programa até achar a entrada especificada.

FILE-CONTROL

Temos as definições de como será feito o acesso ao arquivo. Podemos ter diversas entradas select, uma para cada arquivo. O arquivo pode estar em disco (nosso caso), fita etc.. Será indexado pela chave fs-key e o status fs-stat nos informará o resultado das operações (chave existe, não existe, erro na abertura, etc.). Podemos incluir chaves alternativas e as mesmas poderão ser duplicadas, o que não acontece com a chave principal.

FILE SECTION

Cada arquivo definido em file-control deverá ter uma entrada FD na file section. Aqui informamos o nome do arquivo (poderia estar no select no lugar de DISK) e a estrutura do registro. Inclui um nível em FS-KEY para deixar mais patente que existe a possibilidade de termos uma chave primária composta. Se não sabemos exatamente como será a estrutura do arquivo, é interessante incluirmos um espaço já que os registros são fixos. Alterações posteriores implicariam em fazer um programa para mover os dados da estrutura antiga para a nova. Apesar de não ser difícil é uma etapa desnecessária. O campo FILLER (poderíamos usar um nome como fs-reserva mas filler é mais comum) serve apenas para reservar espaço caso desejarmos adicionar mais alguma informação ao registro. Neste caso, reservamos um espaço de 20 caracteres que poderão ser utilizados posteriormente definido-se os novos campos. Por exemplo, podemos incluir o campo fs-uf pic x(02) e deixamos e alteramos filler para pic x(18).

NIVEL 88 (WS-OPCAO)

Especifica nomes condicionados ao valor da variável melhorando a legibilidade do programa. No caso de ws-opcao, se o usuários selecionar a opção 1 para incluir, é muito mais legível eu verificar if e-incluir do que if ws-opcao=1. É possível especificar mais de um nome como no caso de e-encerrar onde o usuário pode digitar um X maiúsculo ou minúsculo. Também é possível especificar uma faixa. Poderíamos ter e-numerico value is 0 thru 9.

COPY screenio.

Apenas inclui o código de retorno quando o usuário pressionar teclas especiais como Esc, F1, etc.. Utiliza o nível 78 (semelhante ao 88) para deixar o programa mais legível. Temos, por exemplo, 78 COB-SRC-ESC VALUE 2005. e é utilizado cob-src-esc nas comparações em vez de 2005 que não significa nada.

SCREEN SECTION

Aqui definimos as diversas telas do nosso programa. Podemos utilizar display nome que irá apenas mostrar a tela ou accept tela que irá mostrar e solicitar a entrada dos dados existentes. Vale lembra que enter confirma a entrada. Para mudar de um campo para outro é utilizado a tecla Tab (próximo campo) ou Shif+Tab (campo anterior)

Em ss-cls limpamos a tela e mostramos um cabeçalho informando a opção sendo executada (menu, inclusão, exclusão, etc.) e um rodapé que poderá conter alguma informação adicional na última linha. Utilizamos a variável ws-numl que é definida em tempo de execução.

Em ss-menu temos a definição do menu do programa. O auto utilizado na entrada de ws-opcao permite que não seja necessário pressionar enter. Quando o campo é preenchido o programa segue adiante automaticamente. Quando a entrada possui mais de um caractere, use com cautela para que o usuário não se confunda ou seja induzido a erro. Aqui seria mais interessante usar LINE PLUS 1 em vez de informar diretamente o número da linha. Assim, permitiria um deslocamento do menu para cima ou para baixo com mais facilidade.

Em ss-tela-registro temos a definição da tela de entrada para os dados do cliente. Temos níveis diferentes principalmente pela necessidade da entrada apenas da chave para alteração ou inclusão. Não faz muito sentido pedir a entrada de nome e endereço se precisamos apenas do telefone (chave do arquivo). Como observações temos a definição da cor diferente para a entrada do telefone que é utilizada por todos os níveis inferiores. E também dois dos problemas que considero no gnuCOBOL 1 (ainda não solucionados na versão 2). O primeiro é a impossibilidade de entrada da direita para a esquerda que é interessante para valores númericos bem como a limpeza da variável se o primeiro caractere digitado não for de movimentação (setas). O segundo é a não verificação de REQUIRED na entrada dos dados implicando que o usuário faça a consistência via programação, isto é, não tem sentido um cadastro de clientes sem o nome do cliente.

Finalmente temos ss-erro que mostra na linha de rodapé uma mensagem de erro e espera que o usuário pressione enter.

INICIO

Informamos algumas variáveis de ambiente para o programa se comportar como desejamos. No caso, queremos que ele interprete as teclas especiais (principalmente Esc). Como o tempo de espera é muito pequena (1 segundo) e a velocidade dos terminais hoje é muito maior, definimos o tempo em milisegundos (poderíamos ter definido no próprio ambiente, no caso do Linux EXPORT escdelay=25, por exemplo) . Depois obtemos o número de linhas e colunas disponíveis no termina e abrimos o arquivo (que será visto posteriormente).

O próximo passo é o laço para que o usuário selecione a opção desejada e o programa execute a rotina correspondente. Ajustamos e mostramos o cabeçalho e rodapé e esperamos a digitação por parte do usuário. Note que usamos diretamente accept para a tela menu dispensando o display.

Como o ponto encerra uma sentença, é importante que se encerre determinados comandos com o respectivo end (end-if, end-evaluate, etc.). Assim, o compilador emitirá um aviso se alguma coisa estiver errada antes do programador queimar neurônios buscando um erro. Um fácil de cometer é um if com diversos comandos internos e, se existir um ponto antes do desejado, o if também terminará antes. O perform parágrafo thru parágrafo também é importante para que a rotina não seja encerrada antes do desejado.

FINALIZA

Basicamente fecha o arquivo e encerra o programa.

INCLUI

São as rotinas de inclusão dos clientes. Inicialmente ajusta e mostra a tela e entra em um loop para a inclusão do cliente. Foi utilizado GO (TO) mas, para quem acha que não pode, poderia utilizar um PERFORM como no loop do menu em inicio utilizando COB-SRC-ESC com indicador de término.

Na parte de gravação write, não foram feitas maiores verificações a assume-se que um erro seja porque a chave já existe. Note que quando você grava (write) informa o registro (file1-rec) e quando le ou exclui (read ou delete) informa o arquivo (file1).

CONSULTA

Basicamente o mesmo processo de INCLUI porém, como as rotinas de alteração, consulta e exclusão utilizam o mesmo princípio, isto é, apenas a entrada do telefone (chave), foi criada uma rotina para evitar a duplicação do processo no programa. Caso seja pressionado Esc durante a entrada da chave, a rotina coloca 99 em fs-stat indicando fs-cancela e o programa sabe que deve cancelar. Apenas para digitar menos e não precisar verificar cob-src-esc.

ALTERA

Semelhante a CONSULTA porém, após a entrada da chave, solicita a entrada do dados do cliente para a alteração. Todo o registro é regravado.

EXCLUI

Semelhante a rotina de consulta porém, após a entrada da chave a rotina mostra os dados do cliente e solicita a confirmação para a exclusão. Qualquer coisa diferente de sim (S ou s) cancela a exclusão. Só entra no laço se a chave não existe caso contrário, retorna ao menu.

LE-CLIENTE

Espera que o usuário informe a chave. Caso seja pressionado Esc, o programa retorna ajustando fs-stat para fs-cancela. Se ocorreu um erro, assume que o cliente não existe, mostra a mensagem e retorna.

ABRIR-ARQUIVOS.

Como a abertura de um arquivo para entrada e saída (I-O) pressupõe que o arquivo já exista (se for apenas para leitura também). Caso ele não exista (erro 35) o programa abre o arquivo para saída (sempre será sobrescrito), fecha e abre novamente para entrada e saída. Se deixarmos apenas para saída (output) o nosso programa só funcionar para a inclusão de clientes mas precisamos consulta, etc.. Não testamos outros erros e, nestes casos, o nosso programa não funcionará de forma adequada.

MOSTRA-ERRO

Mostra a mensagem de erro no rodapé, espera que o usuário pressione enter (ou alguma tecla e enter) e retorna o rodapé para a mensagem anterior.

Considerações finais

  • Note que você pode facilmente copiar o fonte e, com pequenas alterações, adaptar o programa para outra finalidade. Cadastro de fornecedores, por exemplo. Para facilitar ainda mais, poderíamos mover as mensagens de erro para a working-storage section onde o agrupamento permitiria as alterações com mais facilidade. Basicamente trocar cliente por fornecedor no texto.
  • A inclusão de novos campos ao registro também pode ser feito de forma relativamente simples. Basta adicioná-los ao file1-rec e inclui-os na ss-tela-registro. Como a cláusula required é aceita mas ignorada, será necessário efetuar os testes desejados na inclusão.
Anúncios

por que aprender cobol?

TL;DR

Porque é uma linguagem de programação mais legal que muitas atuais, permite desenvolver facilmente programas mais sérios que muitas linguagens modernas e ainda está sendo utilizada e possui vagas para programadores. Ah, mas …..

Verbosidade?

Se você reclama que precisa escrever muito em COBOL, então você escolheu trabalhar em J certo? Não? Então você só pode estar esperando um futuro onde você pensa no sistema, pressiona enter e os programas se materializam no computador. Não existe outra alternativa. Ah, entendi. Você só está repetindo pois ouviu alguém dizer e acha legal. Sem problema. Mas vejamos o sem graça “Hello World” em Java e em COBOL. A versão Java poderia ser assim:

e em COBOL assim:

Em execução;

Basicamente, 5 linhas em cada linguagem para um programa legível. Ah, mas em Java eu posso escrever tudo na mesma linha. E daí? Vai ficar um programa menos legível e, se você não está em coma desde 1960, em COBOL também é possível escrever tudo na mesma linha. Ah, mas na minha linguagem eu escrevo só: print "Hello World". Grande coisa, poderia apenas digitar um ponto e sair um “hello World” (e pior que tem). Se você reparar, em COBOL é só display "Hello World". O resto serve para facilitar a legibilidade do programa como veremos depois.

É uma linguagem morta!

Realmente. Tanto que existe  vagas no mercado igual a Python ou Ruby e mais do que Pascal, não se escreveriam alguns bilhões de linhas por anos e não haveriam tantos fabricantes oferecendo suas implementações com Micro Focus, IBM, entre outros. Se está morta, não dá dinheiro e as empresas teriam falido. Os artigos irão se basear no GnuCOBOL. Finalmente, alguém de um banco me disse que estavam arrependidos de terem feito um sistema em Java. Deveriam ter feito em COBOL. Isso em 2016.

Por que GnuCOBOL?

Bem, é código aberto, possui uma boa compatibilidade com as versões atuais e existem diversos casos de utilização real e até substituição de ambientes comerciais. A versão estável é a 1.1 mas a 2.0 está em desenvolvimento. Pessoalmente eu acho que na versão estável falta algum polimento na entrada de dados  e a implementação de alguns detalhes. O número de desenvolvedores é pequeno então não espere novidades a cada semana.

Para instalar no Linux, sua distribuição já deve ter em algum repositório ou é só baixar os fontes de site GnuCOBOL, verificar as necessidades, compilar e instalar. Tem um executável para Windows que é só baixar  que a instalação é automática (até poderia ser melhorado para automatizar alguma coisa como a definição dos caminhos).

Você pode usar qualquer editor para criar os programas (agora que existe a possibilidade de um formato mais livre sem a necessidade de iniciar e terminar em colunas específicas. O Emacs e o Vim são duas opções. Tem o OpenCobolIDE que é mais específico para trabalhar com o GnuCOBOL (inicialmente era chamado de OpenCOBOL), o Geany também salienta sintaxe, o Visual Studio 2015 entre outros.

Mas o Dijkstra disse ….

que “O uso de COBOL mutila a mente, o seu ensino deve, portanto, ser considerado como uma infração penal”. Parece que ele não gostava de COBOL, BASIC, APL, etc.. Se ele estivesse vivo, provavelmente falaria mal de Python, Ruby, Java, Go, etc.. O fato é que não existe e, provavelmente nunca existirá, uma linguagem que seja difícil de escrever programas ruins.

A linguagem.

Como o próprio nome diz, COBOL (COmmon Business Oriented Language) é uma linguagem orientada ao uso em negócios. E as atividades de uma empresa pouco mudaram desde o surgimento. São tarefas repetitivas como faturamento, folha de pagamento, contabilidade e outras que podem ser passadas para o computador sem muitas alterações do que é feito manualmente. Se você tem um programa de contabilidade escrito em 1960, o processo provavelmente não sofreu alterações até hoje. Uma empresa que fabrica calçados, poderia usar o mesmo programa ainda hoje (com algumas melhorias é claro e como muitas fazem). Gastar dinheiro comprando programas mais novos está mais para  custo do que investimento.

Outro aspecto importante é que a linguagem já vem (e vinha) com tudo que é necessário para desenvolver um programa para uso comercial. Aproximadamente 99% + 1% da aplicações comerciais necessitam trabalhar com arquivos de dados (clientes, fornecedores, mercadorias, contas a pagar/receber, funcionários, etc. Se fosse utilizada uma linguagem como Pascal, C, etc., seria necessário a escolha de um SGBD (que nem sempre era fácil na época). COBOL pode trabalhar como PostgreSQ, MySQL, etc. mas geralmente é uma preocupação desnecessária em muitos casos (é claro que se o volume de dados for grande e crítico, um bom SGBD é um ótimo complemento).

Como a linguagem foi desenvolvida para que um “leigo pudesse ler e entender”, ela utiliza expressões que podem ser mais facilmente entendidas. Por exemplo, display "Endereço..:" at line 10 column 05 é perfeitamente identificável. Antigamente era mais trabalhoso digitar tudo isso mas os editores modernos podem completar as palavras enquanto se digita, o que facilita bastante e, no caso, é possível digitar display "Endereço..:" at 1005 o que seria praticamente normal para qualquer linguagem.

A linguagem possui divisões, seções e parágrafos e tem um formato parecido com uma receita culinária. Temos:

  • IDENTIFICATION DIVISION que seria a identificação da receita/programa como nome e outras informações.
  • ENVIRONMENT DIVISION que informa o ambiente que será utilizado cozinha, panelas, colheres, forno, etc.
  • DATA DIVISION que possui os dados ou os ingredientes que serão utilizados para o preparo/programa.
  • PROCEDURE DIVISION que diz exatamente como devemos proceder para fazer o bolo ou resolver o problema.

Apesar da estrutura ser mais rígida, os dados são facilmente localizáveis.

Considerações finais.

Eu pretendia falar mais sobre a programação em COBOL mas como ficaria muito longo, fica para o próximo artigo.