1. O trabalho de um programador

Freqüentemente, os programadores iniciantes pensam no trabalho de um programador de maneira completamente diferente de como os programadores experientes pensam nisso.

Os iniciantes geralmente dizem algo como "O programa funciona, o que mais você precisa?" Um programador experiente sabe que "funcionar corretamente" é apenas um dos requisitos para um programa , e nem é o mais importante !

Legibilidade do código

O mais importante é que o código do programa seja compreensível para outros programadores . Isso é mais importante do que um programa funcionando corretamente. Muito mais.

Se você tiver um programa que não funciona corretamente, você pode corrigi-lo. Mas se você tem um programa cujo código é incompreensível, não pode fazer nada com ele.

Basta pegar qualquer programa compilado, como o bloco de notas, e alterar a cor de fundo para vermelho. Você tem um programa funcionando, mas não possui um código-fonte compreensível: é impossível fazer alterações em um programa como esse.

Um exemplo clássico é quando os desenvolvedores da Microsoft removeram o jogo Pinball do Windows porque não podiam portá-lo para a arquitetura de 64 bits. E eles ainda tinham seu código-fonte. Eles simplesmente não conseguiam entender como o código funcionava .

Contabilidade para cada caso de uso

O segundo requisito mais importante para um programa é contabilizar todos os cenários. Muitas vezes, as coisas são um pouco mais complicadas do que parecem.

Como um programador iniciante vê o envio de mensagens SMS:

Um programa funcionando corretamente

Como um programador profissional vê isso:

Um programa funcionando corretamente

O cenário "funciona corretamente" geralmente é apenas um dos muitos possíveis. E é por isso que muitos novatos reclamam do validador de tarefas do CodeGym: apenas um cenário em 10 funciona, e o programador novato acha que é o suficiente.


2. Situações anormais

situações anormais

Situações anormais podem surgir na execução de qualquer programa.

Por exemplo, você decide salvar um arquivo, mas não há espaço em disco. Ou o programa está tentando gravar dados na memória, mas a memória disponível é baixa. Ou você baixa uma foto da Internet, mas a conexão é perdida durante o processo de download.

Para cada situação anormal, o programador (o autor do programa) deve a) antecipá- la, b) decidir exatamente como o programa deve tratá-la e c) escrever uma solução que seja a mais próxima possível da desejada.

É por isso que os programas tiveram um comportamento muito simples por muito tempo: se ocorresse um erro no programa, o programa era encerrado. E essa foi uma abordagem muito boa.

Digamos que você queira salvar um documento em disco, durante o processo de salvamento você descobre que não há espaço em disco suficiente. Qual comportamento você mais gostaria:

  • O programa termina
  • O programa continua em execução, mas não salva o arquivo.

Um programador iniciante pode pensar que a segunda opção é melhor, porque o programa ainda está em execução. Mas na realidade não é assim.

Imagine que você digitou um documento no Word por 3 horas, mas dois minutos depois de começar a escrever ficou claro que o programa não seria capaz de salvar o documento no disco. É melhor perder dois minutos de trabalho ou três horas?

Se o programa não consegue fazer o que precisa, é melhor deixá-lo fechar do que continuar fingindo que está tudo bem. A melhor coisa que um programa pode fazer quando encontra uma falha que não consegue corrigir sozinho é relatar imediatamente o problema ao usuário.


3. Histórico sobre exceções

Os programas não são os únicos que enfrentam situações anormais. Eles também ocorrem dentro de programas — em métodos. Por exemplo:

  • Um método deseja gravar um arquivo no disco, mas não há espaço.
  • Um método deseja chamar uma função em uma variável, mas a variável é igual a null.
  • A divisão por 0 acontece em um método.

Nesse caso, o método chamador possivelmente poderia corrigir a situação (executar um cenário alternativo) se souber que tipo de problema ocorreu no método chamado.

Se estivermos tentando salvar um arquivo em disco e tal arquivo já existir, podemos simplesmente pedir ao usuário para confirmar que devemos sobrescrever o arquivo. Se não houver espaço em disco disponível, podemos exibir uma mensagem ao usuário e solicitar que ele selecione um disco diferente. Mas se o programa ficar sem memória, ele travará.

Antigamente, os programadores refletiam sobre essa questão e chegaram à seguinte solução: todos os métodos/funções devem retornar um código de erro que indique o resultado de sua execução. Se uma função funcionou perfeitamente, ela retornou 0 . Caso contrário, ele retornou um código de erro (não zero).

Com essa abordagem de erros, após quase todas as chamadas de função, os programadores precisavam adicionar uma verificação para ver se a função terminava com um erro. O código aumentou de tamanho e ficou assim:

Código sem tratamento de erros Código com tratamento de erros
File file = new File("ca:\\note.txt");
file.writeLine("Text");
file.close();
File file = new File("ca:\\note.txt");
int status = file.writeLine("Text");
if (status == 1)
{
   ...
}
else if (status == 2)
{
   ...
}
status = file.close();
if (status == 3)
{
   ...
}

Além do mais, muitas vezes uma função que descobriu que ocorreu um erro não sabia o que fazer com isso: o chamador tinha que retornar o erro, e o chamador do chamador o devolvia ao chamador e assim por diante.

Em um programa grande, uma cadeia de dezenas de chamadas de função é a norma: às vezes você pode até encontrar uma profundidade de chamada de centenas de funções. E agora você tem que passar o código de erro de baixo para cima. E se em algum lugar ao longo do caminho alguma função não manipular o código de saída, o erro será perdido.

Outra desvantagem dessa abordagem é que, se as funções retornarem um código de erro, elas não poderão mais retornar os resultados de seu próprio trabalho. O resultado dos cálculos teve que ser passado por meio de parâmetros de referência. Isso tornou o código ainda mais complicado e aumentou ainda mais o número de erros.