Melhorando a Qualidade dos seus Códigos nos Bootcamps
- #JavaScript
- #Java
Olá, humanos.
Nos últimos dias reparei o pessoal compartilhando códigos relacionados aos desafios do Bootcamp Santander (Fullstack Java+Angular) e hoje, em especial, me senti motivado o suficiente para realizar os meus próprios desafios. Durante este processo, tive insights que podem servir de dicas para alguns de vocês.
Sabemos que um dos parâmetros para ganhar pontos no Ranking do bootcamp é a Submissão de Qualidade (SQ), que, como o nome intuitivamente diz, avalia a qualidade dos códigos enviados nos desafios. Apesar de eu honestamente não me importar nenhum pouco com esse sistema de gamificação/pontuação e de não fazer ideia de quais parâmetros a DIO usa de fato para avaliar essa qualidade, vou compartilhar algumas "boas práticas" que >EU< considero serem relevantes na análise.
E, claro, sugestões ou possíveis correções são muito bem-vindas.
Vamos lá. Usarei o primeiro desafio como exemplo (Desafios Full Stack - JavaScript: Equilibrando o Saldo).
1. DECLARAÇÃO E TIPOS DE VARIÁVEIS
Nesse primeiro desafio, a plataforma apresenta três CONSTANTES do tipo NUMBER com conversões explícitas utilizando o método parseFloat:
const saldoAtual = parseFloat(gets());
const valorDeposito = parseFloat(gets());
const valorRetirada = parseFloat(gets());
Minha PRIMEIRA DICA é analisar se a declaração (var, let, const) e o tipo de dado/conversão (number, array, string, int, float, etc) fazem sentido. Será que faz sentido o saldo de uma conta ser uma constante? Não há movimentações bancárias o tempo todo e, portanto, esse saldo não irá mudar eventualmente? Na minha cabeça, sim, por isso faz mais sentido a variável 'saldoAtual' ser de fato uma variável, nesse caso, com declaração 'let' (não vou entrar nos detalhes e diferenças entre var e let, mas qualquer coisa pode me chamar que explico):
let saldoAtual = parseFloat(gets());
const valorDeposito = parseFloat(gets());
const valorRetirada = parseFloat(gets());
Depósitos e saques, no geral, são de fato fixos durante toda uma transação bancária. Claro que há exceções, mas aqui podemos simplificar, então faz sentido eles serem constantes.
De forma análoga, se você olhar o Desafios Full Stack - JavaScript: Condicionalmente Rico, verá que, mesmo inserido basicamente em um contexto idêntico, dessa vez mais simplificado, a plataforma inicialmente declarou as variáveis como LET e a conversão como parseInt.
let saldoTotal = parseInt(gets());
let valorSaque = parseInt(gets());
Lhe pergunto, jovem estudante, por que essa diferença? Eles praticamente inverteram tudo em relação ao primeiro desafio, o que não se justifica já que é o mesmo contexto de transações bancárias. Por isso acredito que eles estão avaliando isso.
O ideal, na minha concepção, é realizar a conversão para float, uma vez que nosso saldo bancário aceita pontos flutuantes (valores decimais ou conjunto dos números Reais, se gostar de matemática). E, novamente, o saque pode ser uma constante, já que não há necessidade de alterar esse valor durante as operações:
let saldoTotal = parseFloat(gets());
const valorSaque = parseFloat(gets());
2. USE FUNÇÕES (DE PREFERÊNCIA ARROW FUNCTIONS)
A SEGUNDA DICA é usar funções para 'modularizar' seus códigos. Não é obrigatório, mas no mundo real você provavelmente nunca irá gerar um código com um 'if/else' jogado aleatóriamente em um arquivo JavaScript.
Uma boa prática é criar funções com objetivos únicos, que realizam apenas uma coisa específica. Por exemplo, em um sistema onde você precisa realizar um saque, o ideal, acredito, seria ter uma função para validar o tipo de dado (se você recebeu números mesmo), uma função para checar se o saldo é suficiente para realizar o saque, outra para realizar a operação e por fim uma função para imprimir o resultado.
Sinceramente, nem eu estou seguindo essa dica aqui porque acho exagerado para desafios tão simples, ao menos nessa parte inicial usando JavaScript. Talvez na parte de Java seja necessário priorizar isso, mas ainda não cheguei lá. De qualquer forma, acho necessário praticar o uso de funções com parâmetros.
Em vez de:
if (saldoTotal >= valorSaque) {
print(`Saque realizado com sucesso. Novo saldo: ${saldoTotal - valorSaque}`)
} else {
print("Saldo insuficiente. Saque nao realizado!")
}
Optar por:
const realizarSaque = (saldoTotal, valorSaque) => {
if (saldoTotal >= valorSaque) {
print(`Saque realizado com sucesso. Novo saldo: ${saldoTotal - valorSaque}`)
} else {
print("Saldo insuficiente. Saque nao realizado!")
}
}
realizarSaque(saldoTotal, valorSaque);
Nesse caso, usei uma Arrow Function porque é algo que preciso aperfeiçoar e parece ser mais utilizado em códigos reais, mas você pode usar sua notação preferida (ou não usar).
Perceba que outra dica implícita é de não criar variáveis desnecessárias. Ao invés de criar uma variável 'saldoDisponivel' para calcular o resultado, por exemplo, eu realizei o cálculo diretamente no método print. Dessa forma, acredito que consuma menos memória/processamento e o cálculo é realizado somente quando necessário, justamente na hora de mostrar a mensagem. Parece mais prático, mas não tenho certeza se de fato é uma boa prática, pensei só na questão de não criar códigos ambíguos/desnecessários.
3. FAÇA VALIDAÇÕES BÁSICAS
Voltando para nosso primeiro desafio, precisamos criar algumas validações, que é a TERCEIRA DICA.
Perceba que só faz sentido a gente sacar ou depositar valores que de fato existam, certo? Não pode ser um valor negativo porque dinheiro negativo é inexistente. Então precisamos checar se o saque ou o depósito possuem valores maiores que zero:
if (valorDeposito < 0 || valorRetirada < 0) {
print(`O valor do depósito ou do saque precisa ser acima de R$ 0`)
}
Mas colocar esses zeros, além de ser muito feio, tira a flexibilidade do nosso sistema. Por exemplo, em um banco X podemos ter valores mínimos de saque e depósito de 100 reais, enquanto no banco Y pode ser 500 reais. Então faz mais sentido a gente criar duas variáveis de depósito e saque mínimos para adaptarmos sempre que necessário:
const valorDepositoMinimo = 200.0
const valorRetiradaMinimo = 10.0
if (valorDeposito < valorDepositoMinimo || valorRetirada < valorRetiradaMinimo) {
print(`Você não possui o valor mínimo para depósito (R$ ${valorDepositoMinimo}) ou o de saque mínimo (R$ ${valorRetiradaMinimo})`)
}
Claro que aqui estou fazendo a validação do saque e do depósito simultaneamente, mas provavelmente o ideal é separar isso (lembra o que falei sobre funções de objetivo único) e melhorar esse print. Aqui eu estou optando por simplificar, por isso criei uma variável única tanto para o valor mínimo do depósito quanto para o saque, facilitando a saída na mesma validação:
const valorMinimo = 100.0
if (valorDeposito < valorMinimo || valorRetirada < valorMinimo) {
print(`O valor do depósito ou do saque precisa ser acima de R$ ${valorMinimo}`)
}
Bom acho que de relevante que eu tinha para falar era isso. Agora basta apenas colocar isso em uma função e arrumar os detalhes estéticos. Optei por usar o método toFixed com duas casa decimais nas outras saídas porque dinheiro é geralmente visto com duas casa decimais na maioria dos sistemas. O resto é só a operação básica de somar o saldo mais o depósito para só depois retirar o saque. E claro, fazer mais uma validação para verificar se há dinheiro suficiente na conta, mas nesse ponto acho que vocês vão conseguir tranquilamente.
De qualquer forma, deixo aqui abaixo meu código completo desse desafio.
// Alterei o saldoAtual para 'let' porque o saldo de uma conta bancária não é constante, durante
// determinados processos ele pode mudar várias vezes. Já o depósito e o saque faz sentido ser constante na maioria dos casos.
let saldoAtual = parseFloat(gets());
const valorDeposito = parseFloat(gets());
const valorRetirada = parseFloat(gets());
// ========================
// Regra mais geral e ideal seria:
// ========================
// const valorDepositoMinimo = 1.0
// const valorRetiradaMinimo = 1.0
// Contudo, nesse caso, para simplificar, assumiremos que tanto
//o valor mínimo de saque quanto o valor mínimo de depósito são iguais.
const valorMinimo = 100.0
const contaBancaria = (saldoAtual, valorDeposito, valorRetirada) => {
if (valorDeposito < valorMinimo || valorRetirada < valorMinimo) {
print(`O valor do depósito ou do saque precisa ser acima de R$ ${valorMinimo.toFixed(2)}`)
}
else if ((saldoAtual + valorDeposito) < valorRetirada){
print(`Seu saldo total na conta é de R$ ${(saldoAtual + valorDeposito).toFixed(2)}, o que não é suficiente para retirar R$ ${valorRetirada.toFixed(2)}.`)
}
else {
print(`Saldo atualizado na conta: ${([saldoAtual + valorDeposito] - valorRetirada).toFixed(1)}`)
}
}
contaBancaria(saldoAtual, valorDeposito, valorRetirada)
Não abordei sobre return, que provavelmente é um tópico importante nesses casos. Então é interessante revisar sobre isso.
Espero que esse textão tenha sido útil para alguém.
Qualquer dúvida é só comentar ou me mandar mensagem por ai.
Abraço.