Solucionado (ver solução)
Solucionado
(ver solução)
7
respostas

Tratamento de exceção relacionada ao método _criaNegociacao (chamado pelo método adiciona)

Olá pessoal!

Antes deste tópico o código (copiado da transcrição) correspondente estava:

// js/app/controllers/NegociacaoController.js

// código anterior omitido

    adiciona(event) {

        event.preventDefault();

        ConnectionFactory
            .getConnection()
            .then(conexao => {

                let negociacao = this._criaNegociacao();

                new NegociacaoDao(conexao)
                    .adiciona(negociacao)
                    .then(() => {
                        this._listaNegociacoes.adiciona(negociacao);
                        this._mensagem.texto = 'Negociação adicionada com sucesso'; 
                        this._limpaFormulario();   
                    });

        })
        .catch(erro => this._mensagem.texto = erro);

    }

//...

Se o usuário digitasse uma data fora do padrão dd/mm/yyyy (definido em aulas anteriores), por exemplo dd/mm/yy, a exceção lançada na classe correspondente era "capturada" pelo catch da Promise no método adiciona(event), porque o código "let negociacao = this._criaNegociacao();" estava dentro da Promise.

Após a mudança de código deste tópico,

// aluraframe/client/js/app/controller/NegociacaoController.js

    adiciona(event) {

        event.preventDefault();

        let negociacao = this._criaNegociacao();

        new NegociacaoService()
            .cadastra(negociacao)
            .then(mensagem => {
                this._listaNegociacoes.adiciona(negociacao);
                this._mensagem.texto = mensagem; 
                this._limpaFormulario();  
            }).catch(erro => this._mensagem.texto = erro);
    }

o código "let negociacao = this._criaNegociacao();" fica fora da Promise, ou seja, a respectiva exceção não é mais capturada pelo catch/exibida para o usuário.

Pensei em envolver o código modificado em um try/catch, mas pensando em padrões de projeto, legibilidade etc (assuntos que estamos vendo cada vez mais ao longo dos 3 cursos avançados de JS), essa seria a solução ideal?Questiono porque desta forma teremos dois "catchs" (o da Promise e o externo do try).

Atenciosamente.

7 respostas

Oi Elías, tudo bem? O problema é o contexto. No primeiro caso, você está em uma camada que se relaciona direto com o banco. No segundo, você tem um service que não necessariamente é o banco.

Mas eu fiquei confuso. Houve uma troca de camadas ai, primeiro estava usando o Factory diretamente pra depois usar um Service.

Olá Wanderson,

Obrigado pelo retorno.

A troca de camadas é proposital, do próprio curso mesmo.

A minha dúvida em si é (mais informações na mensagem acima), como (qual é o padrão para) voltar a tratar a exceção que pode ocorrer na linha de código acima em negrito, que após a mudança ficou fora do catch().

Aguardo vossos comentários.

Atenciosamente

Hm, então Elías, não tem exatamente um padrão. Depende muito do que você quer tratar e se realmente você quer tratar.

Exemplo: Minha aplicação depende muito do banco de dados. Sem ele, nada deve funcionar. Nesse caso, faz sentido tratar o erro? Depende!

A questão aqui é: vou tratar para mostrar uma mensagem bonita pro usuário ou vou tratar para tentar uma alternativa?

Se for tratar para propor uma alternativa, política de retry, por exemplo, na promise do Factory, já faríamos isso. Ai o primeiro catch logo tentaria uma nova conexão.

Agora, se for para mostrar uma mensagem pro usuário de que a aplicação não está disponível no momento. Uma estratégia comum é deixar o erro estourar até o final da pilha de execução onde pode haver algo parecido com um catch que vai mostrar um erro 500 pro usuário, por exemplo.

Isso varia muito por que depende experiência do programador junto dos seus conhecimentos das regras de negócio. Por isso acho difícil indicar um padrão.

Olá Wanderson,

Obrigado pelo retorno. Entendi, não existiria um padrão.

Mas, voltando à questão da primeira mensagem (agora sem considerar um padrão), como você resolveria (código em negrito, que deixou de ter tratamento de exceção)?

Atenciosamente.

Bom, como eu não sei como o seu criaNegociacao está, usei o do curso como referência, esse aqui: https://github.com/alura-cursos/javascript-avancado-iii/blob/master/aluraframe/client/js/app-es6/controllers/NegociacaoController.js

No caso, o método não dispara nenhuma exception. Então eu o deixaria sem tratamento mesmo. Podem haver erros ali? Claro!

Nesse caso, eu usaria um pouco da ideia da política do bom vizinho. Para um dado chegar no controller, entende-se que a view (origem do dado) já tratou de validar o mesmo. Na teoria, seguindo essa ideia, não precisaria tratar e era só seguir em frente. :)

Olá Wanderson,

Obrigado pelo retorno.

O meu criaNegociacao está idêntico ao do link que vocẽ passou.

Acho que entendi o teu ponto de vista sobre a view validar, porém pelo meu entendimento neste curso a validação está ligada ao controller.

Desta forma, gostaria de saber como seria o tratamento desta exceção no controller, porque o tratamento existia até a versão de código da aula anterior, mas ficou de fora da nova versão (detalhes sobre a exceção/tratamento dela nos meus comentários anteriores).

Atenciosamente.

solução!

Opa, então, uma estratégia que podemos estar fazendo é englobar o que queremos fazer no try/catch. Algo como:


try{
    let negociacao = this._criaNegociacao();

        new NegociacaoService()
            .cadastra(negociacao)
            .then(mensagem => {
                this._listaNegociacoes.adiciona(negociacao);
                this._mensagem.texto = mensagem; 
                this._limpaFormulario();  
            }).catch(erro => this._mensagem.texto = erro);
} catch (e){
    console.log(e);
}

Mas como você disse, ter dois catches pode deixar tudo estranho e difícil de ler. Alternativa? Podemos continuar usando try/catch, com um pouco de async await melhorando a legibilidade, etc. Teríamos algo assim:

try{
    let negociacao = this._criaNegociacao();

    const mensagem = await new NegociacaoService().cadastra(negociacao)

    this._listaNegociacoes.adiciona(negociacao);
    this._mensagem.texto = mensagem; 
    this._limpaFormulario();  

} catch (erro){
    this._mensagem.texto = erro;
}

Isso ajuda bastante, mass cria outro problema. o await só pode ser usando dentro de funções async (que criam uma promise por baixo dos panos).

se não quiser fazer o método adicionar ficar com o async, podemos envolver o try/catch em uma função anônima que é assinada com o async. Este último ponto, porém, não me parece uma boa alternativa.