Como tornar o código legível

Como tornar o código legível


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


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


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ó "( 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".

Source: https://habr.com/ru/post/pt421867/


All Articles