
Em algum momento, todos nós escrevemos (e alguns escrevem) códigos ruins, e espero que todos trabalhemos para melhorar nossas habilidades, e não apenas ler artigos como este.
Por que precisamos escrever um bom código, não apenas um código produtivo?
Embora o desempenho do seu produto ou site seja importante, a aparência do seu código também é importante. A razão para isso é que não apenas a máquina está lendo seu código .
Primeiro, mais cedo ou mais tarde, você terá que reler seu próprio código e, quando chegar a hora, apenas um código bem escrito o ajudará a entender o que você escreveu ou a descobrir como corrigi-lo.
Em segundo lugar, se você trabalha em equipe ou colabora com outros desenvolvedores, todos os membros da equipe lerão seu código e tentarão interpretá-lo da maneira que entenderem. Para facilitar para eles, é importante seguir determinadas regras ao nomear variáveis e funções, limitar o comprimento de cada linha e preservar a estrutura do seu código.
Por fim, vejamos um exemplo específico.
Parte 1: Como identificar código incorreto?
A maneira mais fácil de identificar código incorreto, na minha opinião, é tentar ler o código como se fosse uma frase ou frase .
Por exemplo, dê uma olhada neste código:

Captura de tela de uma versão ruim do traverseUpUntil
A função apresentada acima aceita um elemento e uma função condicional e retorna o nó pai mais próximo que satisfaz a função condicional.
const traverseUpUntil = (el, f) => {
Com base no fato de que o código deve ser lido como texto simples, a primeira linha possui três falhas grosseiras.
- Os parâmetros de função não são lidos como palavras .
- Suponha que
el
possa ser entendido, pois esse nome geralmente é usado para denotar um elemento, mas o nome do parâmetro f
não explica nada. - O nome da função pode ser lido assim: "alternar até el passar f", que provavelmente é melhor lido como "alternar até f passar por el". Obviamente, a melhor maneira de fazer isso é permitir que a função seja chamada como
el.traverseUpUntil(f)
, mas esse é outro problema.
let p = el.parentNode
Esta é a segunda linha. Novamente o problema com os nomes, desta vez com a variável. Se alguém olhasse para o código, provavelmente entenderia o que p
. Este é o parentNode
parâmetro el
. No entanto, o que acontece quando olhamos para p
usado em outro lugar, não temos mais um contexto que explica o que é .
while (p.parentNode && !f(p)) {
Na próxima linha, o principal problema que estamos enfrentando é a falta de compreensão do que !f(p)
significa ou faz, porque "f" pode significar qualquer coisa . Supõe-se que a pessoa que está lendo o código deve entender que !f(p)
é uma verificação do nó atual para satisfazer uma determinada condição. Se passar, o ciclo é interrompido.
p = p.parentNode
Tudo está claro aqui.
return p
Não é totalmente óbvio o que é retornado devido a um nome de variável inválido.
Parte 2: Vamos refatorar

Captura de tela de uma boa versão do traverseUpUntil
Primeiro, alteramos os nomes dos parâmetros e sua ordem: (el, f) =>
para (condition, node) =>
.
Você pode estar se perguntando por que, em vez de "elemento ( elemento russo), usei" nó "( nó russo). Usei-o pelos seguintes motivos:
- Escrevemos código em termos de nós, por exemplo
.parentNode
, então por que não torná-lo consistente? - "Nó" é mais curto que "elemento" e o significado não é perdido .
Em seguida, passamos aos nomes das variáveis:
let parent = node
É muito importante divulgar totalmente o valor da sua variável em seu nome , para que "p" agora seja "pai" ( pai russo). Você também deve ter notado que agora não começamos obtendo o pai node.parentNode
, em vez disso, obtemos apenas o nó.
Nós vamos além:
do { parent = parent.parentNode } while (parent.parentNode && !condition(parent))
Em vez do while
usual while
eu escolhi o do ... while
. Isso significa que precisamos obter o nó pai todas as vezes antes de verificar as condições, e não vice-versa. Usar o do ... while
também ajuda a ler código como texto sem formatação.
Vamos tentar ler: "Atribua o nó pai do pai ao pai, desde que o pai tenha um nó pai e a função de condição não retorne true" . Já é muito mais claro.
return parent
Frequentemente, os desenvolvedores preferem usar algum tipo de variável comum ret
(ou returnValue
), mas essa é uma prática muito ruim . Se você nomear suas variáveis de retorno corretamente, torna-se óbvio o que é retornado. No entanto, algumas vezes as funções podem ser longas e complexas, o que leva a muita confusão. Nesse caso, sugiro dividir sua função em várias funções e, se ainda for muito complicada, talvez adicionar comentários possa ajudar.
Parte 3: Simplificação de Código
Agora que você tornou o código legível, é hora de remover o código desnecessário . Estou certo de que alguns de vocês já notaram que não precisamos da variável parent
.
const traverseUpUntil = (condition, node) => { do { node = node.parentNode } while (node.parentNode && !condition(node)) return node }
Simplesmente removi a primeira linha e substitui "pai" por "nó". Então pulei a etapa desnecessária de criar um "pai" e fui direto ao loop.
Mas e o nome da variável?
Embora "nó" não seja a melhor descrição para essa variável, é satisfatório. Mas não vamos parar por aí, vamos renomeá-lo. E o "currentNode"?
const traverseUpUntil = (condition, currentNode) => { do { currentNode = currentNode.parentNode } while (currentNode.parentNode && !condition(currentNode)) return currentNode }
Isso é melhor! Agora, quando lemos o método, sabemos que currentNode
sempre representa o nó em que estamos agora, em vez de ser um nó "de algum tipo".