Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Dúvidas sobre boas práticas

Olá! Fiz o desafio do quiz, exigindo um pouco mais para tentar aprender sobre assincronismo, uso de promises, etc. Basicamente, queria validar que somente uma opção válida foi digitada, e se houve erro, chama-se a pergunta novamente, até o usuário digitar uma opção válida(a, b, ou c).

Em termos de clean code e boas práticas, o que o meu código a seguir tem para melhorar?

const readline = require('readline')

const leitor = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})


console.log('Boas vindas ao Quiz de JavaScript!')
console.log('Responda com a letra correta: a, b ou c\n');

(async () => {
    let acertos = 0
    const pergunta1 = await perguntar('1) Qual palavra usamos para criar uma função?\n(a) define\n(b) function\n(c) create\n> ', 'b')
    if (pergunta1) acertos++

    const pergunta2 = await perguntar('2) Qual dessas é uma estrutura de repetição?\n(a) loopar\n(b) repeat\n(c) for\n> ', 'c')
    if (pergunta2) acertos++

    const pergunta3 = await perguntar('3) Qual valor é considerado falsy em JavaScript?\n(a) 1\n(b) 0\n(c) "texto"\n> ', 'b')
    if (pergunta3) acertos++

    if (acertos === 3) {
        console.log('Parabéns, você gabaritou!')
    } else if (acertos === 2) {
        console.log('Muito bom, continue assim!')
    } else if (acertos === 1) {
        console.log('Bom! Continue estudando')
    } else {
        console.log('Continue praticando e tente novamente!')
    }

    leitor.close()
})()



function perguntar(pergunta, gabarito) {
    return new Promise((resolve) => {
        function iterarPergunta() {
            leitor.question(pergunta, (resposta) => {
                const opcao = resposta.trim().toLowerCase();

                if (!["a", "b", "c"].includes(opcao)) {
                    console.log('Opção inválida. Digite apenas a, b ou c.\n')
                    iterarPergunta()
                } else {
                    resolve(opcao === gabarito)
                }
            })
        }
        iterarPergunta();
    })
}

Além disso, tive um pouco de dificuldade com o uso de IIFE, por não usar ponto e vírgula no console.log antes dele. É recomendado sempre colocar ponto e vírgula em tudo?

Sobre a declaração de função dentro do callback de uma promise, recebi essa dica do GPT, tem alguma outra forma de fazer? Busco saber o que seria mais profissional, em padrão de projeto

Matricule-se agora e aproveite até 50% OFF

O maior desconto do ano para você evoluir com a maior escola de tecnologia

QUERO APROVEITAR
1 resposta
solução!

Oi Augusto, tudo bem? 😊

Seu código está muito bom e demonstra um ótimo entendimento sobre async/await e Promises para lidar com o readline de forma assíncrona! 🤔

Para refinar ainda mais, podemos pensar em algumas melhorias:

  • Separação de Responsabilidades: A função perguntar faz duas coisas: interage com o usuário e valida a resposta. Poderíamos separar isso. A função perguntar poderia apenas retornar a resposta do usuário, e uma outra parte do código cuidaria da validação e da repetição.

  • Tratamento de Erros: Embora você esteja validando as opções "a", "b" ou "c", o código não prevê outros tipos de erros que podem ocorrer durante a interação com o readline.

  • Estrutura do Quiz: Para um quiz maior, ter as perguntas e respostas em uma estrutura de dados (como um array de objetos) facilitaria a iteração e a adição de novas perguntas.

Vamos ver um exemplo de como você poderia refatorar a função perguntar para torná-la mais genérica e como gerenciar as perguntas de forma mais organizada:

const readline = require('readline');

const leitor = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

// Estrutura de dados para as perguntas
const perguntas = [
    {
        texto: '1) Qual palavra usamos para criar uma função?\n(a) define\n(b) function\n(c) create\n> ',
        gabarito: 'b'
    },
    {
        texto: '2) Qual dessas é uma estrutura de repetição?\n(a) loopar\n(b) repeat\n(c) for\n> ',
        gabarito: 'c'
    },
    {
        texto: '3) Qual valor é considerado falsy em JavaScript?\n(a) 1\n(b) 0\n(c) "texto"\n> ',
        gabarito: 'b'
    }
];

// Função para obter uma resposta válida do usuário
function obterRespostaValida(perguntaTexto) {
    return new Promise((resolve) => {
        function iterarPergunta() {
            leitor.question(perguntaTexto, (resposta) => {
                const opcao = resposta.trim().toLowerCase();
                if (!["a", "b", "c"].includes(opcao)) {
                    console.log('Opção inválida. Digite apenas a, b ou c.\n');
                    iterarPergunta(); // Chama novamente se a opção for inválida
                } else {
                    resolve(opcao); // Resolve com a opção válida
                }
            });
        }
        iterarPergunta();
    });
}

// Função principal para rodar o quiz
async function iniciarQuiz() {
    console.log('Boas vindas ao Quiz de JavaScript!');
    console.log('Responda com a letra correta: a, b ou c\n');

    let acertos = 0;

    for (const item of perguntas) {
        const respostaUsuario = await obterRespostaValida(item.texto);
        if (respostaUsuario === item.gabarito) {
            acertos++;
        }
    }

    // Lógica para exibir o resultado (pode ser uma função separada também)
    exibirResultado(acertos);

    leitor.close();
}

// Função para exibir o resultado
function exibirResultado(acertos) {
    if (acertos === perguntas.length) {
        console.log('Parabéns, você gabaritou!');
    } else if (acertos >= perguntas.length - 1) {
        console.log('Muito bom, continue assim!');
    } else if (acertos >= 1) {
        console.log('Bom! Continue estudando');
    } else {
        console.log('Continue praticando e tente novamente!');
    }
}

// Chamada da função principal
iniciarQuiz();

Sobre o uso de ponto e vírgula, a recomendação geral em JavaScript é sempre usar ponto e vírgula (conhecido como ASI - Automatic Semicolon Insertion). Embora o JavaScript muitas vezes consiga inferir onde eles deveriam estar, há casos em que essa inferência pode levar a comportamentos inesperados, especialmente com IIFEs (Immediately Invoked Function Expressions). Usar ponto e vírgula explicitamente torna o código mais previsível e menos propenso a erros sutis. 💪

Quanto à declaração de função dentro do callback de uma Promise, a sua abordagem original com iterarPergunta() dentro do new Promise é uma forma válida de lidar com a recursão necessária para a validação. A refatoração que sugeri acima mantém essa ideia, mas a encapsula em uma função obterRespostaValida que retorna a Promise. Isso é uma prática comum para abstrair a lógica de interação e validação.

Em termos de padrões de projeto, o que você está buscando é a separação de responsabilidades e a abstração. Ao criar funções que fazem uma coisa bem feita (como obterRespostaValida), você torna seu código mais modular, testável e fácil de entender. 💻

🎓 Para saber mais: