Como sabemos, não compilamos código em JavaScript - um ponto negativo que camufla determinados erros que só acontecem em situações especiais e/ou quando o usuário já está usando a aplicação. Por isso a adoção de boas práticas e políticas de testes em JavaScript é fundamental. Vejamos um exemplo de boas práticas em JavaScript, exibindo mensagens de erro através de abstração.

Passo 1: O problema de não usar abstração

Métodos de abstração são funções que ocultam os detalhes de implementação das mesmas. Vamos ver como a abstração pode ajudar na vida real.

Abordagem incorreta: Por exemplo, na Listagem 1 temos um tipo de mecanismo de exibição de avisos sistêmicos.

Listagem 1. Exemplo de função para tratamento de erros/avisos.


function converterIdade(idade) {
 if (!_.isString(idade)) throw new Error("Uma string era esperada");
 var a;
 console.log("Tentativa de converter uma idade ");
 a = parseInt(idade, 10);
 if (_.isNaN(a)) {
   console.log(["Não pode converter a idade:", idade].join(' '));
   a = 0;
 }
  return a;
 }
Run

Essa função, embora não seja abrangente o suficiente para converter strings de idade, é bem ilustrativa. O uso da função converterIdade pode se dar da seguinte maneira:


converterIdade("42");
converterIdade(42);
converterIdade("abc");
  • Linha 1: O primeiro exemplo recebe um valor em string e efetua a conversão com sucesso, exibindo o resultado 42 no console.
  • Linha 2: lança um error: Uma string era esperada em vista do tipo de dado do parâmetro não ter sido enviado corretamente.
  • Linha 3: lança uma mensagem “Não pode converter a idade: abc” justamente porque o dado passado sequer representa um número, seja em string ou tipo numérico.

Problema: A função converter idade funciona como está escrito, mas se você desejar modificar a maneira em que os avisos são apresentados, as mudanças precisarão ser feitas nas linhas apropriadas, e em qualquer outro lugar onde padrões semelhantes são usados – levando a reescrita desnecessária de código.

Passo 2: Usando abstração

Solução: Uma abordagem melhor é “abstrair” a noção de avisos em funções, padronizando assim o código, tal como temos na Listagem 2.

Listagem 2. Exemplo de funções para tratar erros e mensagens.


function fail(msg) {
 throw new Error(msg);
}
function warn(msg) {
 console.log(["AVISO:", msg].join(' '));
}
function note(msg) {
 console.log(["NOTA:", msg].join(' '));
}
Run

Veja que apenas encapsulamos o comportamento que antes estava solto no código, assim podemos reusar tais funções em qualquer lugar ao longo da nossa implementação. Usando essas funções, a função converterIdade pode ser reescrita da mesma forma que vemos na Listagem 3.

Listagem 3. Nova função converterIdade com uso das funções de erro/aviso.


function converterIdade(idade) {
 if (!_.isString(idade)) fail("Uma string era esperada");
 var a;
 note("Tentativa de converter uma idade ");
 a = parseInt(idade, 10);
 if (_.isNaN(a)) {
   warn(["Não pode converter a idade:", idade].join(' '));
   a = 0;
 }
  return a;
 }
Run

Portanto, ao tentar executar o novo código, seu comportamento se dará de forma semelhante, porém com logs mais apropriados:


1. converterIdade("frob");
2.   // (console) AVISO: Não pode converter a idade: frob
3.   // Saída: 0

Não é muito diferente do antigo comportamento, exceto que agora a ideia de erros de report foram abstraídas. O report pode, assim, ser modificado completamente a bel prazer, tal como vemos na Listagem 4.

Listagem 4. Modificando comportamento das mensagens.


function note() {}
function warn(msg) {
 alert("Isso não parece uma idade válida");
}
converterIdade("abc");
// (alert box) Isso não parece uma idade válida
// Saída: 0