roger-melo-treinamentos / curso-de-js-roger-melo

Repositório de informações do CJRM
491 stars 170 forks source link

Aplicação: Quiz #5609

Closed Dan-Padovani closed 1 year ago

Dan-Padovani commented 1 year ago

As cores da sua versão da aplicação são diferentes das cores da aplicação mostrada na aula?

Sim

A aplicação contém funcionalidades que não foram mostradas nas aulas?

Não

A aplicação contém funcionalidades da linguagem que não foram mostradas nas aulas?

Não

Link do repositório da aplicação (ou pasta pública no Google Drive)

https://github.com/Dan-Padovani/App01-Quiz-CJRM

Maiores dificuldades durante a implementação

As maiores dificuldades foram em determinar um ponto de parada nas implementações de pequenos detalhes do quiz.

Exemplo: Se deveria iniciar o quiz com algumas opções pré-selicionadas (igual visto na aula, pois isso mudou um pouco o fluxo da lógica em construir a aplicação). Quais áreas de clique eu fecharia o popup com a pontuação? Se deveria validar a ocorrência de respostas em branco (essa validação eu fiz). Gostaria de ter usado o método reset() no formulário quando o usuário clica no botão "tentar novamente" assim os elementos clicados seriam zerados mas esse reset não fiz pois não foi apresentado em aula. Entre outros pequenos detalhes que não foram especificados ou solicitados na descrição do exercício, mas acredito que faz parte do desafio, porém preciso aprender a definir esse ponto de parada na implementação de pequenos detalhes, uma vez que o que foi pedido está rodando.

Menores dificuldades durante a implementação

Prefiro não citar menores dificuldades pois achei que foi equilibrado, inclusive tive que revisar algumas anotações ou consultar a documentação no mdn de 2 métodos, então não sei se posso dizer que houve "menores" dificuldades, mas aprendi muito com o desafio e alguns métodos foram bem automáticos ao usar.

MivlaM commented 1 year ago

Olá @Dan-Padovani.

Passando para dizer que a issue foi visualizada e em até 10 dias úteis a análise será feita =)

MivlaM commented 1 year ago

Olá, @Dan-Padovani.

Parabéns pelo esforço em construir a primeira aplicação do treinamento =)

Quais áreas de clique eu fecharia o popup com a pontuação?

Você fez bem, entretanto, a única que eu acrescentaria é a de clique fora do popup.

Se deveria validar a ocorrência de respostas em branco (essa validação eu fiz).

Não precisa se preocupar muito com isso no início, o mais importante no momento que estamos analisando uma aplicação é ver se o aluno assimilou e conseguiu compreender bem o que foi falado até aqui.

Gostaria de ter usado o método reset() no formulário quando o usuário clica no botão "tentar novamente" assim os elementos clicados seriam zerados mas esse reset não fiz pois não foi apresentado em aula.

Legal! Não é pq não avaliamos o que não é mostrado no CJRM que você não pode usar no portfólio futuramente =)

As maiores dificuldades foram em determinar um ponto de parada nas implementações de pequenos detalhes do quiz.

Sem problemas, você pode adicionar novas funcionalidades na sua aplicação conforme você for progredindo no treinamento e aprendendo mais coisas. Por enquanto, nesse momento, recomendo que a aplicação que você for enviar para a análise, não tenha muitas funcionalidades que tenham um funcionamento muito distinto do que é apresentado nas aulas. Mas, você pode adicioná-las depois =)

Vou deixar abaixo algumas observações sobre sua aplicação.


Boas Decisões

Você entendeu que não era necessário manipular DOM dentro do forEach (um erro comum que algumas pessoas cometem). A ideia do forEach ali naquele momento era apenas calcular os pontos, exatamente como vc fez =)

O parâmetro do callback do forEach foi nomeado de forma coerente, como singular de itens do array no qual o forEach foi encadeado. Isso dá mais legibilidade ao ler a expressão userAnswer === correctAnswer[index].

Uma ideia interessante que você teve em relação à usabilidade foi a de posicionar a mensagem dos pontos de forma que ela preenchesse boa parte do centro da tela após clicar no botão. Isso é bom pois a pontuação aparece justamente onde o usuário estará olhando após enviar as respostas.


Comentários no código

Não é uma regra, mas evite comentários.

Você usou um comentário para indicar o enunciado do exercício. Mas, atente-se que comentários podem mentir. Se o código for modificado e o comentário correspondente não for atualizado, o comentário perde o sentido. Em breve, em exercícios posteriores, vai ser pedido para você enviar a aplicação para a produção (subir no netlify), então o ideal seria ter apenas o código referente às funcionalidades da aplicação. Isso sem mencionar o retrabalho de atualizar comentários para mantê-los em dia.


Input na label

Prefira deixar o input dentro da label, como foi mostrado nas aulas. Fazendo isso, o usuário não precisa posicionar o mouse e clicar exatamente no input type radio. Basta clicar no texto da alternativa. A ideia aqui é tornar mais fácil a usabilidade da aplicação. Veja um exemplo abaixo:

<!-- Antes -->
<input type="radio" name="inputQuestion1" value="A" />
  <label class="form-check-label">
     Seventh Heaven
  </label>
<!-- Depois -->
<label class="form-check-label">
  <input type="radio" name="inputQuestion1" value="A" />
    Seventh Heaven
</label>

Inputs desmarcados por padrão

Antes do usuário selecionar as alternativas, é bom que a primeira alternativa de cada pergunta esteja marcada por padrão. Para fazer isso, basta inserir o atributo checked no input type radio a ser marcado por padrão.

// antes
<input type="radio" name="inputQuestion1" value="A">
// depois
<input type="radio" name="inputQuestion1" value="A" checked>

Isso é mais uma preferência pessoal, mas acho que incentiva o usuário a marcar a resposta que ele realmente acredita que seja a verdadeira.


Nomenclatura

Se você achar que faz sentido, uma sugestão seria renomear a const h3Score para scoreMessage, a ideia aqui é caso futuramente o elemento mudar para h2, por exemplo, a const não precisará ser renomeada, pois a nomenclatura da const estará escrita de forma mais abrangente.

// antes
const h3Score = document.querySelector('.popup-content h3')
// depois
const scoreMessage = document.querySelector('.popup-content h3')

Se fizer sentido para você, você também pode renomear a const handleQuiz para showScore. O intuito aqui é fazer com que o nome tenha um sentido mais próximo para o que a função está fazendo, que é exibir a pontuação.

// antes
const handleQuiz = event => {
  // ...
}
// depois
const showScore = event => {
  // ...
}

Há também um ajuste que pode ser feito na const correctAnswer, para se tornar mais claro o que ela está armazenando, pode ser interessante renomeá-la para a sua versão no plural, visto que ela está armazenando as respostas corretas dos inputs, e não apenas uma. Por isso, a sugestão aqui é colocá-la como correctAnswers:

// antes
const correctAnswer = ['A', 'B', 'B', 'A']
// depois
const correctAnswers = ['A', 'B', 'B', 'A']

refactoring userAnswers

A abordagem é a seguinte. Vamos criar uma função especificamente para obter as respostas do usuário. Essa função pode se chamar getUserAnswers, nela podemos criar uma const userAnswer que vai receber uma expressão que pega o valor de cada inputQuestion do form. userAnswers vai receber um array vazio que será preenchido após percorrermos cada item dentro do array correctAnswers por meio do método forEach. Ficaria assim:

const getUserAnswers = () => {
  const userAnswers = []

  correctAnswers.forEach((_, index) => {
    const userAnswer = form[`inputQuestion${index + 1}`].value
    userAnswers.push(userAnswer)
  })

  return userAnswers
}

Tudo certo até aqui? Se sim, vamos prosseguir! A ideia do código acima é a seguinte, baseado em um array, você quer obter um novo array que contém a mesma quantidade de itens do array original. Por quê? correctAnswers tem quatro itens e userAnswers quando está sendo retornado também vai ter quatro itens. Quando baseado em um array, você precisa obter um novo array com a mesma quantidade de itens do array original, você pode usar um método chamado map. Se você não entender completamente o funcionamento desse método agora, não se preocupe, pois ele será mais aprofundado nas aulas posteriores, você pode, de qualquer forma, revisar essa análise quando chegar na parte do treinamento cujo método map é abordado. Sabendo disso, ao invés de userAnswers ser declarada como um array vazio, o userAnswers pode receber o retorno dessa expressão. Feito isso, ao invés de executar o método push, é necessário apenas retornar userAnswers. Veja abaixo:

const getUserAnswers = () => {
  const userAnswers = correctAnswers.map((_, index) => {
    const userAnswer = form[`inputQuestion${index + 1}`].value
    return userAnswer
  })

  return userAnswers
}

Feito isso, você pode refatorar a função ainda mais ao usar os retornos implícitos das arrow functions, removendo os blocos e retornos:

const getUserAnswers = () => correctAnswers.map((_, index) => form[`inputQuestion${index + 1}`].value)

Fazendo isso, o map vai ser executado para cada item de correctAnswers, o callback está retornando o valor da resposta do usuário, esse valor que o callback está retornando vai ser inserido num novo array que o map está gerando por baixo dos panos. Quando esse callback for executado para todos os itens, o map vai retornar esse novo array que ele gerou e toda a expressão vai resultar no array que o map retornou.

Por fim, você pode invocar a função dentro da função showScore que o código funcionará normalmente =)


Includes ao invés de some

Uma sugestão aqui, se você achar que faz sentido, é renomear a const isAEmptyAnswer para hasEmptyAnswer. O intuito é tornar a nomenclatura dela mais simples e mais próxima do que ela está exercendo na aplicação. Portanto, acredito que seja mais próximo de ler se "há uma resposta vazia" do que "é uma resposta vazia".

// antes
const isAEmptyAnswer = userAnswers.some(userAnswer => userAnswer === '')
// depois
const hasEmptyAnswer = userAnswers.some(userAnswer => userAnswer === '')

Aqui, vale a pena destacar um detalhe, a lógica de hasEmptyAnswer pode ser refatorada com o método includes ao invés de some. A vantagem aqui, é simplificar o código, deixando-o muito mais curto, conciso e ainda funcionando da mesma forma que anteriormente.

// antes
const hasEmptyAnswer = userAnswers.some(userAnswer => userAnswer === '')
// depois
const hasEmptyAnswer = userAnswers.includes('')

Função showPopupInfo

Se fizer sentido para você, você pode renomear a função showPopupInfo para showPopupMessage, é uma sugestão que deixa o nome mais específico para o papel que ela está desempenhando no código, quando a pessoa bater o olho no nome, pode ser mais fácil para ela entender o que esse trecho está fazendo na aplicação como um todo.

// antes
const showPopupInfo = message => {
// ...
}
// depois
const showPopupMessage = message => {
// ...
}

Um pequeno detalhe que vale a pena observar, a invocação de showPopupMessage dentro de showScore pode receber uma string normal ao invés de uma template string. Prefira usar esta última apenas quando for necessário uma interpolação, por exemplo, de resto, a sugestão é a de manter o código padronizado com uma string normal para facilitar a leitura do mesmo.

// antes
if (hasEmptyAnswer) {
  showPopupMessage(`Por favor, responda todas perguntas ;)`)
  return
}
// depois
if (hasEmptyAnswer) {
  showPopupMessage('Por favor, responda todas perguntas ;)')
  return
}

Mensagem de 0 pontos

Quando o usuário faz 0 pontos, 'Poxa, não foi dessa vez =(', não é bem uma mensagem que deixa isso claro. Dizer que a pontuação foi 0 é uma notícia triste, mas a sugestão aqui é que ela precisa ser comunicada com clareza. Portanto, o que você pode fazer, se achar interessante, é deixar o usuário mais consciente do progresso dele no quiz em relação à pontuação total. Vc pode fazer isso com uma mensagem indicando a pontuação com porcentagem ("você acertou 50%") ou inserindo uma barra e pontuação total do quiz após a quantidade de acertos, exemplo: "Poxa, não foi dessa vez, sua nota final é de 0/100 =(".


getScore e getScoreMessage

Feito esses ajustes, logo em seguida vou te mostrar algumas abordagens de refactoring usando métodos que você vai encontrar em breve nas aulas seguintes, ambos serão explicados com detalhes futuramente. O que quero que você entenda, nesse primeiro momento, é o conceito por trás deles. Sabendo disso, observe o código abaixo:

const calculatePoints = (userAnswer, index) => {
  const isACorrectAnswer = userAnswer === correctAnswers[index]

  if (isACorrectAnswer) {
      score += 25
  }
}

Toda a ideia do código acima é a seguinte: baseado em um array, você quer gerar um número, isto é, um número que seja a pontuação. E quando baseado num array você quer gerar um número, você pode fazer isso de forma funcional, sem efeito colateral e sem reatribuições e ainda pode diminuir algumas linhas do código. A forma que você pode fazer isso é, por exemplo, por meio do método reduce(). Mas como isso pode ser feito? Vamos lá, acompanhe comigo codando passo a passo. Você pode criar uma função própria para obter a pontuação, essa função se chamará getScore, vamos declarar um parâmetro que também se chamará userAnswers e esse parâmetro também tera um default parameter de array vazio. Por esse momento, vamos manter uma lógica similar à seguinte:

const getScore = (userAnswers = []) => {
  userAnswers.forEach((userAnswer,index) => {
    const isACorrectAnswer = userAnswer === correctAnswers[index]

    if(isACorrectAnswer){
      score += 25
    }
  })
}

Na lógica acima, o array que armazena as respostas do usuário está sendo percorrido por um forEach e para cada resposta verdadeira segundo a lógica armazenada pela const isAnswerCorrect, uma pontuação de 5 pontos está sendo adicionada a let score. Agora, quero que atente-se às modificações que vamos fazer nessa lógica. A let score que antigamente recebia o valor 0, agora vai ser uma const score e irá receber o retorno da expressão que antes era do forEach, mas agora contém o método reduce. O reduce vai receber um parâmetro chamado accumulator e como segundo argumento, ele irá receber um valor inicial 0. Por quê 0? Porque 0 é o ponto de partida do valor que você deseja obter na pontuação e porque é uma boa prática usar o segundo argumento do reduce para indicar visualmente o tipo de valor que o reduce deve retornar. Feito isso, se a resposta estiver correta, o valor de accumulator somado com 25 será retornado, se a condição do if não for verdadeira, apenas o valor de accumulator vai ser retornado, ficaria assim:

const getScore = (userAnswers = []) => {
  const score = userAnswers.reduce((accumulator,userAnswer,index) => {
    const isACorrectAnswer = userAnswer === correctAnswers[index]

    if(isACorrectAnswer){
      return accumulator + 25
    }

    return accumulator
  }, 0)

  return score
}

Na primeira execução dessa função, accumulator vai receber o segundo argumento do reduce, userAnswer vai receber o primeiro item do array e o index é o mesmo index do item do array. Se a resposta estiver correta, a função vai retornar accumulator + 25, que na primeira execução será (0 + 25). Por outro lado, se a resposta não estiver correta, accumulator será retornado (na primeira execução, o accumulator estará armazenando 0). Quando a função for executada pela segunda vez, o parâmetro accumulator estará armazenando o valor que foi retornado na execução passada da função, então se na primeira execução for retornado accumulator + 25, na segunda execução o parâmetro accumulator estará armazenando 25 ao invés de 0 como na primeira execução. Assim, a operação será feita novamente. E isso vai se repetir para cada item do array userAnswers. A const score está recebendo o resultado dessa expressão e por fim, esse valor é retornado.

Há mais algumas refatorações que você pode fazer para o código se tornar ainda mais conciso, você pode eliminar os returns para aproveitar o return implícito da arrow function e ao invés de usar o bloco de if, você pode usar um ternário, você também ira aprender mais sobre o ternário posteriormente, mas para você ter uma ideia, se o que está a esquerda do sinal de ? for um valor truthy, accumulator + 25 é retornado, caso contrário, apenas accumulator será retornado. O score pode ser retornado diretamente:

// Usando o operador ternário no lugar do bloco do if
const getScore = (userAnswers = []) => { 
  return userAnswers.reduce((accumulator, userAnswer, index) => {
    return userAnswer === correctAnswers[index] ? accumulator + 25 : accumulator
  }, 0)
}
// Usando o return implícito das arrow functions
const getScore = (userAnswers = []) => userAnswers
  .reduce((accumulator, userAnswer, index) => userAnswer === correctAnswers[index] ? accumulator + 25 : accumulator, 0)

Por fim, você pode remover as funções addToScore e checkAnswers e invocar a função getScore() dentro da função showScore recebendo o array armazenado por userAnswers como argumento. Fazendo isso, a let score não precisa mais ser global =)

const showScore = event => {
  // ...
  const score = getScore(userAnswers)
 // ...
}

Legibilidade em funcionalidades que a gente ainda não conhece na linguagem pode ser algo um pouco complicado no começo, porém quanto mais você praticar, mais você vai se acostumar com esse tipo de código declarativo. Percebe-se que a função foi resumida em apenas duas linhas =)

Há mais uma abordagem de refactoring que podemos fazer envolvendo a parte do código responsável para indicar qual mensagem será selecionada de acordo com a pontuação do usuário. Estou me referindo a esses trechos de código em específico:

const showFinalPointsInformation = score => {
  const isThereAnyPoints = score > 0

  if (isThereAnyPoints) {
    showPopupMessage(`Legal, Você marcou ${score}/100 pontos! =)`)
    return
  }
  showPopupMessage('Poxa, não foi dessa vez, sua nota final é de 0/100 =(')
}

Há uma maneira de refatorar essa parte do código e deixá-la muito mais concisa e enxuta. Preparado? Vamos lá então!

Você percebe um padrão se repetindo e que apenas alguns dados específicos estão mudando? O que muda é a mensagem que o usuário recebe quando a pontuação for 0. Sabendo disso, podemos criar uma função para fazer o papel para essa e as outras condições, vamos criar uma função para retornar uma string que vai conter todas as informações para o caso retratado no if. Se a condição do if está relacionada a mensagem de pontuação, podemos criar uma função chamada getScoreMessage que irá receber a pontuação que o usuário fez por meio de um parâmetro score que fará o mesmo papel de definir a mensagem que o usuário receberá e que retornará esse objeto personalizado para cada caso. Visto que a mensagem se repete caso a pontuação seja qualquer outro valor que não seja 0, podemos fazer a função retornar um objeto em que há o 0 e como propriedade uma string de mensagem final. Para as outras situações, não será preciso inserir essa opção no objeto, podemos fazer com que essas informações sejam retornadas por meio de um || caso a pontuação não seja 0. Ficaria assim:

const getScoreMessage = score => {
  return {
    0: 'Poxa, não foi dessa vez, sua nota final é de 0/100 =(' }
  [score] || `Legal, Você marcou ${score} pontos! =)`
}

Depois disso, vamos criar uma const message que vai armazenar o retorno da invocação de getScoreMessage. Feito isso, todo aquele trecho de código mostrado no início dessa refatoração pode ser excluído. Apenas o trecho de código necessário para essa funcionalidade dentro de showScore será o de inserção das propriedades da função no DOM, assim conseguimos fazer com que o código faça a mesma coisa que o anterior antes de começar a refatoração e eliminamos muitas linhas desnecessárias. O código completo na showScore ficaria assim:

const showScore = event => {
  event.preventDefault()
  const userAnswers = getUserAnswers()
  const score = getScore(userAnswers)

  const hasEmptyAnswer = userAnswers.includes('')

  if (hasEmptyAnswer) {
    showPopupMessage('Por favor, responda todas perguntas ;)')
    return
  }

  const message = getScoreMessage(score)
  showPopupMessage(message)
}

closePopup

Se você quiser que o código fique mais simples, uma sugestão é usar includes ao invés de some na const shouldClosePopup. Por meio desse método, você pode verificar se as classes armazenadas pelo array classNameToClose estão incluídas na const classNameClickedElement. Aqui, também vale o detalhe de que há mais de uma classe dentro do array, portanto, como a observação mencionada no início da análise, pode ser mais interessante em quesitos de legibilidade, renomeá-la para sua forma no plural. Ficaria assim:

// antes
const shouldClosePopup = classNamesToClose.some(classname => classname === classNameClickedElement)
// depois
const shouldClosePopup = classNamesToClose.includes(classNameClickedElement)

Uma outra sugestão seria, se você achar que faz sentido, fazer um destructuring ao invés de usar a sintaxe de colchetes na const classNameClickedElement. Você pode tornar o código mais legível ao usar uma abordagem envolvendo o destructuring. Nessa const, a sintaxe de colchetes está sendo usada para pegar o primeiro elemento do array ao clicar em qualquer lugar na tela. Isso também pode ser feito por meio do destructuring. Ao envolver por colchetes a const classNameClickedElement, você está colocando-a na primeira posição no destructuring de array, ou seja, o primeiro item do array vai para a essa const, pois ela se torna o primeiro item do destructuring. A função refatorada por completo ficaria assim:

// antes
const classNameClickedElement = event.target.classList[0]
// depois
const [classNameClickedElement] = event.target.classList

Nas aulas seguintes, você verá outras formas de refatorar o código dessa aplicação.

Mais uma vez, parabéns pelo esforço =)

As observações fizeram sentido?

Dan-Padovani commented 1 year ago

Olá MivlaM

Eu estou fazendo a revisão das listas de exercícios, desde o feedback do meu código mas há alguns pontos que não entendi ainda. Muito do que foi apontado consegui entender, alguns pontos como o refactoring userAnswers, do modo que é apresentado na aula eu entendi mas o método map ainda não está claro pra mim, fora que de fato não havia passado por ele nas aulas também.

Uma coisa que não entendi nele é porquê temos que fazer 2 returns, me refiro a este trecho aonde temos o return de correctAnswer e fora do metodo map temos um outro return que é correctAnswers

const getUserAnswers = () => {
  const userAnswers = correctAnswers.map((_, index) => {
    const userAnswer = form[`inputQuestion${index + 1}`].value
    return userAnswer
  })

  return userAnswers
}

Eu dei uma olhada nos 3 métodos, map, filter e reduce, até porque o reduce também foi utlizado no refactoring da getScore e como ainda não fiz a revisão desse conteúdo, estou com um pouco de dificuldade nesse momento para entender melhor esses trechos.

Eu acredito que assim revisando os métodos mais vezes e realizando os exercícios do mesmo (coisa que ainda não fiz por travei), será mais fácil entender a sugestão apontada.

Mas o que me deixou ainda mais 'preocupado' foi o fato de não conseguir abstrair este trecho, há alguma aula que posso refazer para reforçar a forma como trabalhamos o retorno de objeto dessa fora?

const getScoreMessage = score => {
  return {
    0: 'Poxa, não foi dessa vez, sua nota final é de 0/100 =(' }
  [score] || `Legal, Você marcou ${score} pontos! =)`
}

Eu não entendi muito bem o motivo de chamar essa propriedade de 0 e fora do objeto (das chaves me refiro) passarmos [score] com essas || Não poderia ser algo no sentido de ter essa propriedade 0: mensagem..., propriedade 1: outra mensagem... Ou seja como se fosse 2 propriedades? Teria algum materia que você recomenda para entender melhor o que foi feito nessa etapa?

Gostaria de uma orientação melhor, sobre o retorno implícito de arrow functions, isso foi feito no refactoring das funções aonde teve o map e o reduce apresentados. Minha dúvida é, de fato fica bem menor o código e tudo em uma linha praticamente, mas até que ponto isso é indicado e quando?

Pois acho que foi até o professor Roger já falou que nem sempre resumir tipo 4 linhas em 1 não é algo que garante uma legibilidade melhor e olhando ambos os trechos, (pelo menos nesse momento que ainda estou em busca da fluência) não achei tão legível.

Em ambos os momentos o código é apresentado de forma mais legível e mais claro logo acima do mesmo, sendo possível entender o que está acontecendo (mesmo com minha difuculdade atual no map e reduce), até porque o JavaScript já faz muitas coisas por debaixo dos panos, com isso achei um pouco menos legível esse retorno implícito de diversas arrow functions, talvez quando chegar a pleno ou sênior, isso não tenha tanta diferença, será?

Nesse momento do curso eu decidi revisar / refazer todas as 20 listas de exercícios que já fiz até aqui, estou refazendo e tomando nota de onde as vezes eu demoro mais para resolver. Entretanto, um dos pontos que até cheguei a pedir ajuda no grupo (isso se refere nas útimas listas de exercícios), é sobre a refatoração. Pois eu consigo muitas vezes resolver o problema, nem sempre igual ao do professor, mas após a revisão observo como foi feito e procuro seguir o mesmo caminho ao refazer novamente do 0, porém na maioria das vezes acabo deixando passar algum trecho sem refatorar e isso estava me consumindo em diversos sentidos, inclusive tempo. Eu tive ótimos conselhos ali mas sempre ao ver essas diferenças, parece que tudo aquilo volta e sinto que talvez não aprendi direito ou suficiente, pois como o professor ilustrou, o CJRM é como uma "demão" de tinta ou seja, não é na primeira vez que a pontura fica boa, pois precisa de mais "demãos"para realmente ficar bonita.

Desde já agradeço o feedback, pois realmente gerou dicas excelentes, só preciso ainda saber equilibrar essa questão de refatoração e funcionalidades a mais para publicar minha aplicação devidamente refatorada e com mais alternativas =)

Desde já agradeço.

Como disse anteriormente, eu vou terminar a revisão e também vou refatorar esse código seguindo esses conselhos e também adicionar mais algumas funcionalidades antes de subir como destaque no github, pois vejo que preciso melhorar muito esse código, fora entender melhor o map, filter e reduce que sempre vejo o pessoal falando no grupo.

Roger-Melo commented 1 year ago

Olá @Dan-Padovani.

Uma coisa que não entendi nele é porquê temos que fazer 2 returns

A função de callback do map precisa retornar o valor que vc quer inserir no novo array que o map está gerando:

correctAnswers.map((_, index) => {
  // ...
  return userAnswer // 👈🏻 retorna o valor que deve ser inserido no array que o map está gerando
})

Lembre-se que a função será executada para cada item do array. Depois disso, a expressão arr.map(...) irá retornar o array que o map gerou.

A const userAnswers está armazenando o array que a expressão arr.map(...) retornou:

// 👇🏻 armazenou o array que o map retornou
const userAnswers = correctAnswers.map(/* ... */)

Dentro da função getUserAnswers, após userAnswers armazenar o array que o map gerou, userAnswers está sendo retornada:

const getUserAnswers = () => {
  const userAnswers = correctAnswers.map(/* ... */)

  // 👇🏻 retorna o valor que userAnswers armazena (array)
  return userAnswers
}

Isso significa que quando getUserAnswers for invocada, ela irá retornar o array userAnswers.

Faz sentido?


Mas o que me deixou ainda mais 'preocupado' foi o fato de não conseguir abstrair este trecho, há alguma aula que posso refazer para reforçar a forma como trabalhamos o retorno de objeto dessa fora?

Tem que ficar preocupado não. Há muitos conceitos que vão demandar muita prática. Vc não vai entender tudo "de primeira", e isso é natural =)

A notação obj[...] ainda será mostrada várias vezes no treinamento, mas aqui eu explico em quais casos vc vai precisar usar ela.

O que foi mostrado como refactoring da getScoreMessage é basicamente o que foi mostrado no exercício 09 nessa aula. A diferença é que após os colchetes, foi usado um curto-circuito.

Curto-circuito é um assunto que vc verá à partir da etapa 11, então não precisa se preocupar com isso por agora =)


...mas até que ponto isso é indicado e quando?

Isso é subjetivo e/ou depende do time em que vc está.

Vc ainda será exposto a muitos casos de uso de retorno implícito e conforme for praticando, terá mais kilometragem para decidir como prefere fazer.


Está ficando mais claro? =)

Dan-Padovani commented 1 year ago

Perfeito professor Roger, clareou muito!

Eu vou continuar no ritmo que conversamos, essa é a "primeira demão", vou focar em revisar os pontos que realmente eu sentir que preciso absorver melhor tal conceito, ciente que novos exemplos irão contribuir com essa evolução, claro que sem deixar de seguir o método do curso, juntamente com a revisão raio x quando necessário.

Estou fechando essa issue pois não tenho mais nenhuma dúvida dos pontos abordados.

Desde já agradeço a todos!