O controverso comando GO TO

Photo by Moritz Mentges on Unsplash

Combatido pelas patrulhas das melhores práticas e banido de linguagens mais novas como Java e Phyton, mesmo profissionais de TI com pouca experiência em programação COBOL acreditam piamente que o GO TO é um mal que precisa ser combatido. Mas existe alguma situação em que seu uso possa ser justificado?

O início da controvérsia

Já nas primeiras discussões do comitê encarregado de desenvolver o ALGOL, no final dos anos 1950, havia discussões sobre a necessidade ou não de se implementar nesta linguagem um comando que permitisse um desvio de controle incondicional.

Essa polêmica ganhou visibilidade no meio acadêmico em 1968, quando o cientista holandês Edsger Dijkstra publicou um artigo intitulado “A Case Against GO TO Statement”, que depois Niklaus Wirth – editor da revista Communications of Association for Computing Machinery – rebatizou de “GO TO statement considered harmful”.

Neste artigo, Dijkstra afirma que esse comando deveria ser abolido de todas as linguagens de programação de alto nível, uma vez que prejudicava a análise e a compreensão do código fonte e poderia ser evitado em todas as situações.

A transcrição do artigo original pode ser lida aqui.

A afirmação de Dijkstra, claro, causou reações de apoio e críticas furiosas, com muitos defendendo que o problema era o uso indiscriminado do comando, mas que a própria legibilidade do código dependia do uso correto do GO TO, em determinadas situações.

Só o GO TO?

Algumas vezes tenho a impressão de que determinadas palavras ganham mais importância do que os conceitos que tentam expressar.

Por exemplo, houve um tempo em que eu fazia propostas de projetos para manutenção de sistemas. Havia um dogma na empresa onde eu trabalhava que não podia ser questionado, sob pena de excomunhão: nenhuma frase da proposta poderia conter a expressão “et cetera” ou “etc.”.

A alegação era de que o cliente poderia interpretar este “etc.” como qualquer coisa, o que, na prática, deixaria o projeto com o escopo aberto.
Eu sempre tentei argumentar que não eram os caracteres “e”, “t”, “c”, “.” que ameaçavam o projeto, e sim o uso irresponsável dessa expressão sem considerar o contexto. Uma frase do tipo “o sistema permitirá que faturas sejam incluídas, alteradas, excluídas, consultadas etc.” certamente levaria a enormes discussões com o cliente no futuro. Mas algo como “o usuário informará o código internacional da moeda, previamente cadastrado (USD para Dólar, GBP para Libra etc.)” não teria nenhum efeito devastador.

Com o comando GO TO acredito que aconteça uma coisa parecida. É a expressão “vá para” que deve ser banida dos programas? O comando break e continue dentro de um loop não são também uma forma de instruir o programa para “ir para” algum lugar? A famosa combinação “try / catch / finally” do Java não têm também um GO TO implícito em todas as instruções?

Um loop gigante escrito em C cheio de breaks e continues ou um try a 480 quilômetros do seu catch em Java, comprometem a legibilidade e as futuras manutenções de um programa. E o mesmo acontece com um GO TO utilizado indiscriminadamente.

O GO TO no COBOL

O COBOL possui comandos para loops e cases, como diversas outras linguagens. O uso do GO TO, por esse motivo, seria tecnicamente dispensável. Mas existem situações em que seu uso facilita a leitura do programa e sua manutenção no futuro.

Vamos analisar um caso prático. O trecho abaixo é um parágrafo de um programa real, que tem por objetivo validar campos preenchidos pelo usuário:

/----------------------------------------------------------------*
* OBJETIVO : VALIDAR INFORMACOES FORNECIDAS PELO USUARIO
*----------------------------------------------------------------*
 R12-VALIDA-TELA.
 
     MOVE "SIM" TO WT-FL-ERRO
     IF   AIS0108A-DE-REFERENCIA = SPACES
          MOVE "Nome Nao Preenchido." TO AIS0108A-TX-MSG
          MOVE 04 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     IF   AIS0108A-NM-LOGRADOURO = SPACES
          MOVE "Endereco Nao Preenchido." TO AIS0108A-TX-MSG
          MOVE 05 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     IF   AIS0108A-NM-BAIRRO = SPACES
          MOVE "Bairro Nao Preenchido." TO AIS0108A-TX-MSG
          MOVE 06 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     IF   AIS0108A-NM-CIDADE = SPACES
          MOVE "Cidade Nao Preenchida." TO AIS0108A-TX-MSG
          MOVE 07 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     IF   AIS0108A-CD-UF = SPACES
          MOVE "Estado Nao Preenchido." TO AIS0108A-TX-MSG
          MOVE 09 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     IF   AIS0108A-CD-UF NOT = SPACES
          MOVE AIS0108A-CD-UF TO XXVEST-CD-ESTADO
          CALL "XXVEST" USING XXCOMUM-PARAMS, XXVEST-PARAMS
          CANCEL "XXVEST"
          IF   XXVEST-RC-CODE NOT = ZEROS
               MOVE "Estado Invalido." TO AIS0108A-TX-MSG
               MOVE 09 TO WT-NR-CAMPO
               GO TO SR12
          END-IF
     END-IF
     IF   AIS0108A-CD-CEP1 = ZEROS AND
          AIS0108A-CD-CEP2 NOT = ZEROS
          MOVE "CEP Invalido." TO AIS0108A-TX-MSG
          MOVE 10 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     IF   AIS0108A-NM-CONTATO = SPACES
          MOVE " Contato Não Informado." TO AIS0108A-TX-MSG
          MOVE 11 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     IF   AIS0108A-TX-EMAIL = SPACES
          MOVE "E-Mail Não Informado." TO AIS0108A-TX-MSG
          MOVE 12 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     IF   AIS0108A-TX-RAMO = SPACES
          MOVE "Ramo Principal Não Informado." TO AIS0108A-TX-MSG
          MOVE 13 TO WT-NR-CAMPO
          GO TO SR12
     END-IF
     MOVE "NAO" TO WT-FL-ERRO.
 SR12. EXIT.

Neste trecho temos dez comandos GO TO que desviam o fluxo para o final do parágrafo (SR12[1]) quando algum erro é identificado.

Agora vejamos como ficaria esse parágrafo numa instalação que simplesmente proibisse a utilização do GO TO, sem exceções.

/----------------------------------------------------------------*
* OBJETIVO : VALIDAR INFORMACOES FORNECIDAS PELO USUARIO
*----------------------------------------------------------------*
 R12-VALIDA-TELA.
     MOVE "SIM" TO WT-FL-ERRO
     IF AIS0108A-NM-CLIENTE = SPACES
        MOVE "Nome Nao Preenchido." TO AIS0108A-TX-MSG
        MOVE 04 TO WT-NR-CAMPO
     ELSE
        IF AIS0108A-NM-LOGRADOURO = SPACES
           MOVE "Endereco Nao Preenchido." TO AIS0108A-TX-MSG
           MOVE 05 TO WT-NR-CAMPO
        ELSE
           IF AIS0108A-NM-BAIRRO = SPACES
              MOVE "Bairro Nao Preenchido." TO AIS0108A-TX-MSG
              MOVE 06 TO WT-NR-CAMPO
           ELSE
              IF AIS0108A-NM-CIDADE = SPACES
                 MOVE "Cidade Nao Preenchida." TO AIS0108A-TX-MSG
                 MOVE 07 TO WT-NR-CAMPO
              ELSE
                 IF AIS0108A-CD-UF = SPACES
                    MOVE "Estado Nao Preenchido." TO
                         AIS0108A-TX-MSG
                    MOVE 09 TO WT-NR-CAMPO
                 ELSE
                    IF AIS0108A-CD-UF NOT = SPACES
                       MOVE AIS0108A-CD-UF TO XXVEST-CD-ESTADO
                       CALL "XXVEST" USING XXCOMUM-PARAMS
                                           XXVEST-PARAMS
                       CANCEL "XXVEST"
                       IF XXVEST-RC-CODE NOT = ZEROS
                          MOVE "Estado Invalido." TO
                               AIS0108A-TX-MSG
                          MOVE 09 TO WT-NR-CAMPO
                       ELSE
                          IF AIS0108A-CD-CEP1 = ZEROS AND
                             AIS0108A-CD-CEP2 NOT = ZEROS
                             MOVE "CEP Invalido." TO
                                  AIS0108A-TX-MSG
                             MOVE 10 TO WT-NR-CAMPO
                          ELSE
                             IF AIS0108A-NM-CONTATO = SPACES
                                MOVE "Contato Não Informado." TO
                                     AIS0108A-TX-MSG
                                MOVE 11 TO WT-NR-CAMPO
                             ELSE
                                IF AIS0108A-TX-EMAIL = SPACES
                                   MOVE "E-Mail Não Informado."
                                     TO AIS0108A-TX-MSG
                                   MOVE 12 TO WT-NR-CAMPO
                                ELSE
                                   IF AIS0108A-TX-ATIVIDADE =
                                      SPACES
                                      MOVE
                                "Ramo Principal Não Informado."
                                      TO AIS0108A-TX-MSG
                                      MOVE 13 TO WT-NR-CAMPO
                                   ELSE
                                      MOVE “NAO” TO WT-FL-ERRO
                                   END-IF
                                END-IF
                             END-IF
                          END-IF
                       END-IF
                    END-IF
                 END-IF
              END-IF
           END-IF
        END-IF
     END-IF.
 SR12. EXIT.

Há quem prefira esse formato por ser mais “estruturado”. Eu, particularmente, acho que dificulta a manutenção do programa sem agregar nenhum outro valor.

Repare que tivemos que alterar a edentação de algumas linhas para não ultrapassar o limite da coluna 72. Poderíamos ter reduzido os nomes das variáveis ou as mensagens exibidas para o usuário mas, convenhamos, essa teria sido uma solução pobre.

E esse nem é o maior problema. Imagine, por exemplo, que no futuro precisemos inserir três novos campos nessa tela, entre os NM-CLIENTE e NM-LOGRADOURO. Além de ter que refazer toda a edentação das linhas subsequentes, fatalmente ficaríamos ainda mais “imprensados” na coluna 72, tendo que desalinhar os comandos ou quebrá-los em várias linhas. E tudo isso para que? Para evitar o uso de um comando rápido (um GO TO gera apenas uma instrução jump em código de máquina) que não afetaria em nada a legibilidade do programa.

Conclusão

Todo padrão de codificação deve se preocupar com:

  • Performance
  • Segurança
  • Clareza
  • Facilidade em manutenções futuras

Qualquer regra que não tenha uma das quatro justificativas acima deveria ser descartada. Infelizmente, não é incomum encontrar instalações que estabelecem restrições irracionais e injustificáveis.

Qualquer um que já tenha participado de reuniões de trabalho para definição de padrões de codificação sabe que normalmente elas terminam com amizades desfeitas, ódio, rancor e ranger de dentes.

Regras de programação estão mais associadas a preferências pessoais do que a argumentos técnicos. Programar, como vivo repetindo, é mais parecido com artesanato do que com engenharia.

E é bom justamente por isso.

[1] Para ser tecnicamente correto, SR12 não é o “final” do parágrafo R12-VALIDA-TELA; ele apenas marca até onde o comando PERFORM deve ir.


3 comentários sobre “O controverso comando GO TO

  1. Primeiramente, excelente texto!

    Mas sigo com uma dúvida que creio que seja comum entre os iniciantes:

    Nessa situação utilizando o GO TO, se o perform “R12-VALIDA-TELA” estiver em uma condição de repetição (“faça até” ou “faça enquanto”), exemplo: UNTIL, o programa continuaria dentro do loop UNTIL?

    Para ficar mais claro:

    ROTINA-PRINCIPAL.

    PERFORM R12-VALIDA-ARQUIVO THRU SR12
    UNTIL WS-FIM-ARQUIVO.

    Obrigado!

Deixe um comentário

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