Bug do milênio: depois a gente pensa nisso

Photo by Paulo Henrique Macedo Dias from Pexels

Em 1958, Bob Bemer, da IBM, tentou alertar programadores, a própria IBM, agências do governo e a ISO que a prática de representar anos com dois dígitos levaria a um grande problema na virada do século. O problema chegou, e ficou conhecido como bug do milênio ou Y2K.

1958. Antes do nascimento do COBOL. E ele passou os vinte anos seguintes insistindo nesse assunto.

O Cenário

Não foi só inércia que fez com que o problema se arrastasse e se agravasse ao longo do tempo. Havia sim uma justificativa técnica para que a prática do ano com dois dígitos não fosse alterada nos anos posteriores a 1958.

A indústria do processamento de dados para fins comerciais estava praticamente começando. Os recursos de hardware eram escassos e caros. Numa época em que dados e programas eram armazenados em cartões perfurados com 80 colunas, economizar dois bytes em cada data fazia todo sentido.

Um computador como o IBM 1401, lançado em 1959, contava com apenas 2 kilobytes de memória. Todo bit precisava ser economizado, e as manobras para otimizar o uso de recursos tão limitados não se restringiam apenas à eliminação do século nos campos data.

O mercado financeiro foi o primeiro a enfrentar as consequências do bug do milênio, já nos anos 1980, quando o governo americano começou a emitir títulos com vencimento posterior a 31/12/1999. Nessa época, a Bolsa de Nova York comunicou que havia alocado 100 programadores, num projeto de 20 milhões de doláres, para remediar a situação.

A grande maioria das empresas, porém, esperou pelo menos mais uns 15 anos para enfrentar o problema de forma efetiva. E, ao menos em parte, essa espera tem a ver com o momento que se vivia naquela época.

Entre o final dos 1980 e meados dos 1990 havia uma crença de que o downsizing pudesse este e outros problemas da tecnologia da informação. A promessa de redes menores, mais flexíveis e escaláveis absorvendo a carga de trabalho dos grandes mainframes sugeria também a possibilidade de substituição daqueles sistemas que teriam problemas na virada do século. Dali a vinte anos o futuro seria o Clipper, o Visual Basic, o Delphi, o Power-Builder… e o COBOL já estaria morto.

Surpreendentemente, para alguns, o que aconteceu foi o contrário: o downsizing foi eficaz para alguns sistemas marginais (que foram reescritos mais de uma vez desde que nasceram), enquanto o COBOL – junto com Natural, Easytrieve, ALGOL, PL/I e outros – continuou moendo bilhões de transações por dia nas grandes organizações.

O bug

Os efeitos do bug podiam ser vários, indo desde os mais inofensivos como a exibição de uma data errada em telas e relatórios, até os mais preocupantes, como monumentais erros de cálculo, crash de sistemas críticos e impacto em máquinas e equipamentos controlados por computador.

Mas, basicamente, a causa do bug estava na incapacidade de se realizar comparações e operações aritméticas com datas cujo ano estivesse representado por apenas dois dígitos.

Uma simples comparação de datas, como mostrada na figura abaixo, poderia produzir resultados incorretos e levar os sistemas a consequências imprevisíveis. Embora a data de pagamento tenha sido 28/12/1999, o sistema consideraria que ela ocorreu depois de 05/01/2000.

Figura 1.

As Soluções

Na última metade dos anos 1990 ficou claro que (1) os sistemas continuavam tratando datas exatamente como antes, (2) os sistemas críticos não haviam sido substituídos, (3) 1999 viraria 2000, com sistema ou sem sistema.

Diversas soluções foram sugeridas para resolver ou contornar um problema que tinha data e hora para acontecer. As duas principais abordagens adotadas pelo mercado foram Expansão e Janelamento.

Expansão

A solução óbvia, que Bob Bemer sugeriu 40 anos antes: transformar datas 9(6) em 9(8), AAMMDD em AAAAMMDD, AAMM em AAAAMM, e todas as suas variações, colocando dois dígitos a mais para o ano.

A dificuldade agora era que não havia meia dúzia de sistemas com algumas centenas de programas. Eram milhões de sistemas, bilhões de programas e trilhões de linhas de código que tinham que ser analisadas, alteradas e testadas.

A expansão ainda trazia outros desafios: se eu ponho dois bytes a mais num campo data de um registro de arquivo, eu mexo no tamanho desse registro. Logo, tenho que alterar todos os programas que consomem esse arquivo (seja ele sequencial, indexado ou relativo) mesmo que não utilizem aquela data que provocou a expansão.

Um impacto muito maior e com muito mais riscos envolvidos, não necessariamente ligados ao tratamento de datas. Essa abordagem foi adotada por quem começou mais cedo e tinha tempo e dinheiro.

Janelamento

Essa solução implicava encontrar campos data, identificar os pontos que necessitavam de intervenção (comparação entre datas e operações artiméticas, principalmente) e implementar um tratamento específico nesses pontos sem alterar o tamanho de campos, registros e arquivos.

O impacto seria menor, pois as intervenções seriam pontuais. O esforço de teste, consequentemente, seria significativamente reduzido.

O processo de janelamento, em linhas gerais, consistia em:

  • Encontrar todas as datas com 6 ou 4 dígitos dentro dos fontes e rastreá-las para descobrir onde e como eram utilizadas e que outras estruturas poderiam ser impactadas por elas.
  • Definir um ano pivot que pudesse ser usado para determinar se uma data pertencia ao século XX ou ao século XXI. Por exemplo, se 40 fosse adotado como pivot, então 17/12/55 seria considerado século XX (17/12/1955, porque 55 é maior que o ano pivot 40) e 23/04/05 seria considerado século XXI (23/04/2005, porque 05 é menor que o ano pivot 40).
  • Criar uma subrotina para comparar uma data com o ano pivot e retornar uma data temporária expandida.
  • Usar essa data temporária expandida apenas nos comandos afetados.

Para ficar mais claro, imagine um programa com as linhas abaixo:

...
FILE SECTION.
FD ARQUIVO.
01 REGISTRO.
    03 MT-ALUNO      PIC 9(007).
    03 DT-PAGAMENTO  PIC 9(006).
    03 DT-VENCIMENTO PIC 9(006).
...
WORKING-STORAGE SECTION.
...
PROCEDURE DIVISION.
...
IF DT-PAGAMENTO > DT-VENCIMENTO
    PERFORM CALCULA-MULTA
END-IF
...

Os campos DT-PAGAMENTO e DT-VENCIMENTO são variáveis de 6 dígitos que guardam datas no formato AAMMDD, e por isso podem ser usados na comparação. Para corrigir o problema sem alterar o tamanho do registro teríamos que criar variáveis de trabalho na WORKING e alterar o IF, como mostrado em amarelo no trecho abaixo:

...
FILE SECTION.
FD ARQUIVO.
01 REGISTRO.
    03 MATRICULA     PIC 9(007).
    03 DT-PAGAMENTO  PIC 9(006).
    03 DT-VENCIMENTO PIC 9(006).
...
WORKING-STORAGE SECTION.
77 TMP-DT-PAGAMENTO  PIC 9(008) VALUE ZEROS.
77 TMP-DT-VENCIMENTO PIC 9(008) VALUE ZEROS. 
...
PROCEDURE DIVISION.
...
CALL "JANELAMENTO" USING DT-PAGAMENTO TMP-DT-PAGAMENTO
CALL "JANELAMENTO" USING DT-VENCIMENTO TMP-DT-VENCIMENTO
IF TMP-DT-PAGAMENTO > TMP-DT-VENCIMENTO
    PERFORM CALCULA-MULTA
END-IF
...

Naturalmente, essa é apenas uma das muitas formas de implementar a solução de janelamento. Muitas empresas, com receio de que programas externos pudessem afetar a performance dos sistemas, optaram por deixar a conversão de datas em um parágrafo que era inserido no programa via COPY.

Essa solução, claro, não era definitiva. Em algum momento no futuro, ao redor do ano pivot, tudo voltaria a dar errado. Mas, como se dizia na época, “até lá já teremos substituído esses sistemas”.

Para quem escolheu 40 como pivot, metade do tempo já passou.

Conclusão

Bilhões foram gastos em todo o mundo para evitar a crise a tempo. A partir de 1998, países como Portugal importavam programadores COBOL de onde fossem.

Todas as empresas dispararam seus projetos Y2K ao mesmo tempo. Não havia nem prestadoras de serviço nem mão-de-obra suficiente. Lembro de profissionais já aposentados sendo disputados por mais de uma consultoria, pessoas que só trabalharam com terminais 3278 e que não sabiam usar um mouse porque haviam saído do mercado antes dos PCs, empresas que contratavam primeiro e só depois procuravam mesas e cadeiras para botar todo mundo sentado, programadores NATURAL sendo improvisados em projetos de renovação COBOL, e vice-versa… Um pandemônio que durou dois anos.

Haverá um outro bug do milênio?

Seguramente não nas proporções do Y2K, mas já se começa a discutir aqui e ali alguns desafios que serão enfrentados nos próximos anos.

Quem escolheu um pivot baixo, como 30 por exemplo, tem dez anos para pensar numa solução. Pode ser pouco, se pensarmos no que aconteceu entre 1958 e 2000.

Um outro bug, conhecido como Y2K38, é esperado para o ano 2038: o tipo time_t, do Unix, armazena data e hora como a quantidade de segundos transcorridos desde 01/01/1970, em uma variável signed long integer, disponível nos sistemas de 32 bits. Acontece que o valor máximo que esse tipo pode armazenar é 2 elevado a 31 menos 1, o que vai estourar exatamente em 2038.

Mas até lá dá tempo.


Deixe um comentário

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