JavaScript é da web inicial. No início, foram escritos scripts simples que "animavam" as páginas dos sites. Agora, o JS se tornou uma linguagem de programação completa que pode até ser usada para desenvolver projetos do lado do servidor.
Os aplicativos da web modernos dependem muito do JavaScript. Isso é especialmente verdadeiro para aplicativos de página única (aplicativo de página única, SPA). Com o advento de bibliotecas e estruturas como React, Angular e Vue, o JavaScript se tornou um dos principais componentes dos aplicativos da Web.

O dimensionamento desses aplicativos, seja sobre as partes do cliente ou do servidor, pode ser uma tarefa muito difícil. Se esses aplicativos forem baseados em uma arquitetura mal pensada, seus desenvolvedores enfrentarão, mais cedo ou mais tarde, certas limitações. Eles estão se afogando em um mar de surpresas desagradáveis.
O autor do artigo, cuja tradução estamos publicando hoje, deseja compartilhar dicas sobre como escrever código JavaScript puro. Ele diz que o artigo é para programadores de JS de qualquer nível de habilidade. Mas será especialmente útil para aqueles que estão familiarizados com JavaScript, pelo menos em um nível intermediário.
1. Isolamento de código
Para manter a base de código do projeto limpa, para que o código possa ser lido com facilidade, é recomendável que os fragmentos de código sejam separados em blocos separados com base em sua finalidade. Esses blocos geralmente são funções. Considero esta recomendação a mais importante que posso dar. Se você estiver escrevendo uma função, deve se concentrar imediatamente no fato de que essa função teria como objetivo solucionar um único problema. A função não deve ser projetada para resolver vários problemas.
Além disso, você deve se esforçar para garantir que as chamadas de função não levem a efeitos colaterais. Na maioria dos casos, isso significa que a função não deve alterar algo declarado fora dela. Os dados são recebidos através de parâmetros. Ela não deve trabalhar com mais nada. Você precisa
return
qualquer uma das funções usando a palavra-chave
return
.
2. Divisão do código em módulos
As funções usadas de maneira semelhante ou executam ações semelhantes podem ser agrupadas em um módulo (ou, se desejar, em uma classe separada). Suponha que você precise fazer vários cálculos em seu projeto. Em tal situação, faz sentido expressar os diferentes estágios de tais cálculos na forma de funções separadas (blocos isolados), cujas chamadas podem ser combinadas em cadeias. No entanto, todas essas funções podem ser declaradas em um único arquivo (ou seja, em um módulo). Aqui está um exemplo do módulo de cálculo.js que contém funções semelhantes:
function add(a, b) { return a + b } function subtract(a, b) { return a - b } module.exports = { add, subtract }
E aqui está como você pode usar este módulo em outro arquivo (vamos chamá-lo de
index.js
):
const { add, subtract } = require('./calculations') console.log(subtract(5, add(3, 2))
Os desenvolvedores de aplicativos front-end podem receber as seguintes recomendações. Para exportar as entidades mais importantes declaradas no módulo, use as opções de exportação padrão. Para entidades secundárias, você pode usar a exportação nomeada.
3. Use vários parâmetros de função em vez de um único objeto com parâmetros
Ao declarar uma função, você deve se esforçar para usar vários parâmetros, em vez de um único objeto com parâmetros. Aqui estão alguns exemplos:
A presença de uma função com vários parâmetros permite que você descubra imediatamente o que precisa ser passado para ela, observando a primeira linha de sua declaração. Esta é precisamente a razão pela qual dou essa recomendação.
Apesar de, ao desenvolver funções, você precisa se esforçar para garantir que cada uma delas resolva apenas um problema, o tamanho do código da função pode ser bastante grande. Se uma função aceita um único objeto com parâmetros, para descobrir exatamente o que ela espera, talvez seja necessário examinar todo o seu código, gastando muito tempo com ele. Às vezes, pode parecer que, ao trabalhar com funções, é muito mais fácil usar um único objeto com parâmetros. Mas se você escrever funções, considerando o possível dimensionamento futuro do aplicativo, é melhor usar vários parâmetros.
Note-se que existe um certo limite após o qual o uso de parâmetros individuais perde seu significado. No meu caso, esses são quatro a cinco parâmetros. Se uma função precisar de tanta entrada, o programador deve considerar o uso de um objeto com parâmetros.
O principal motivo dessa recomendação é que os parâmetros individuais esperados pela função devem ser passados para ela em uma ordem específica. Se alguns dos parâmetros forem opcionais, você precisará passar funções como
undefined
ou
null
. Ao usar um objeto com parâmetros, a ordem dos parâmetros no objeto não importa. Com essa abordagem, você pode fazer sem definir os parâmetros opcionais como
undefined
.
4. Reestruturação
A reestruturação é um mecanismo útil que apareceu no ES6. Permite extrair os campos especificados dos objetos e gravá-los imediatamente nas variáveis. Pode ser usado ao trabalhar com objetos e módulos:
Em particular, ao trabalhar com módulos, faz sentido importar para um arquivo não o módulo inteiro, mas apenas as funções necessárias, fornecendo nomes compreensíveis. Caso contrário, você terá que acessar funções usando uma variável que simboliza o módulo.
Uma abordagem semelhante é aplicável aos casos em que um único objeto é usado como parâmetro de função. Isso permite que a primeira linha da função descubra imediatamente o que exatamente ela espera receber como um objeto com parâmetros:
function logCountry({name, code, language, currency, population, continent}) { let msg = `The official language of ${name} ` if(code) msg += `(${code}) ` msg += `is ${language}. ${population} inhabitants pay in ${currency}.` if(contintent) msg += ` The country is located in ${continent}` } logCountry({ name: 'Germany', code: 'DE', language 'german', currency: 'Euro', population: '82 Million', }) logCountry({ name: 'China', language 'mandarin', currency: 'Renminbi', population: '1.4 Billion', continent: 'Asia', })
Como você pode ver, apesar de a função aceitar um único objeto com parâmetros, sua desestruturação permite descobrir o que exatamente precisa ser colocado nela quando a função é chamada. A próxima dica será sobre como informar com mais precisão ao usuário o que a função espera.
A propósito, a reestruturação também pode ser usada ao trabalhar com componentes funcionais do React.
5. Defina valores padrão para os parâmetros de função
Os valores padrão dos parâmetros das funções, os valores padrão dos parâmetros, faz sentido usar ao destruir objetos com parâmetros e, nesses casos, quando as funções aceitam listas de parâmetros. Primeiramente, ele fornece ao programador um exemplo de quais funções podem ser passadas. Em segundo lugar, permite descobrir quais parâmetros são obrigatórios e quais são opcionais. Complementamos a declaração da função do exemplo anterior com os valores padrão dos parâmetros:
function logCountry({ name = 'United States', code, language = 'English', currency = 'USD', population = '327 Million', continent, }) { let msg = `The official language of ${name} ` if(code) msg += `(${code}) ` msg += `is ${language}. ${population} inhabitants pay in ${currency}.` if(contintent) msg += ` The country is located in ${continent}` } logCountry({ name: 'Germany', code: 'DE', language 'german', currency: 'Euro', population: '82 Million', }) logCountry({ name: 'China', language 'mandarin', currency: 'Renminbi', population: '1.4 Billion', continent: 'Asia', })
É óbvio que, em alguns casos, se um parâmetro de função não foi passado para ele ao chamar uma função, é necessário cometer um erro em vez de usar o valor padrão desse parâmetro. Porém, freqüentemente, porém, a técnica descrita aqui é muito útil.
6. Não passe dados desnecessários para funções
A recomendação anterior nos leva a uma conclusão interessante. Consiste no fato de que as funções não precisam transferir os dados que não precisam. Se você seguir esta regra, o desenvolvimento de funções poderá exigir tempo adicional. Mas, a longo prazo, essa abordagem levará à formação de uma base de código que se distingue pela boa legibilidade. Além disso, é incrivelmente útil saber que tipo de dados é usado em cada local específico do programa.
7. Limitando o número de linhas nos arquivos e o nível máximo de aninhamento de código
Eu vi arquivos grandes com código de programa. Muito grande Alguns tinham mais de 3.000 linhas. Nesses arquivos, é muito difícil navegar.
Como resultado, é recomendável limitar o tamanho dos arquivos medidos em linhas de código. Normalmente, me esforço para garantir que o tamanho dos meus arquivos não exceda 100 linhas. Às vezes, quando é difícil dividir uma certa lógica em pequenos fragmentos, o tamanho dos meus arquivos atinge de 200 a 300 linhas. E muito raramente, seu tamanho atinge 400 linhas. Arquivos que excedem esse limite são difíceis de ler e manter.
No decorrer dos trabalhos em seus projetos, crie com ousadia novos módulos e pastas. A estrutura do projeto deve se parecer com uma floresta composta por árvores (grupos de módulos e arquivos de módulos) e ramificações (seções de módulos). Esforce-se para garantir que seus projetos não sejam como montanhas.
Se falarmos sobre a aparência dos próprios arquivos com o código, eles devem ser semelhantes ao terreno com colinas baixas. Trata-se de evitar grandes níveis de aninhamento de código. Vale a pena se esforçar para garantir que o aninhamento do código não exceda quatro níveis.
Talvez a observação dessas recomendações ajude a aplicar as regras apropriadas do ESLint linter.
8. Use ferramentas para formatar automaticamente o código
Ao trabalhar em projetos JavaScript em uma equipe, você precisa desenvolver um guia claro para o estilo e a formatação do código. Você pode automatizar a formatação de código com o ESLint. Esse linter oferece ao desenvolvedor um enorme conjunto de regras personalizáveis. Existe um
eslint --fix
que pode corrigir alguns erros.
No entanto, eu recomendo usar o Prettier em vez do ESLint para automatizar a formatação do código. Com essa abordagem, o desenvolvedor pode não precisar se preocupar com a formatação do código. Ele só precisa escrever programas de qualidade. Todo o código formatado automaticamente usando um único conjunto de regras parecerá consistente.
9. Use nomes de variáveis bem projetados
O nome da variável deve refletir idealmente seu conteúdo. Aqui estão algumas diretrizes para selecionar nomes de variáveis informativos.
▍ Funções
Normalmente, as funções realizam algum tipo de ação. As pessoas, quando falam sobre ações, usam verbos. Por exemplo - converter (converter) ou exibir (mostrar). Recomenda-se que os nomes das funções sejam formados para que comecem com um verbo. Por exemplo,
convertCurrency
ou
displayUser
.
▍Arrays
Matrizes geralmente contêm conjuntos de alguns valores. Como resultado, faz sentido adicionar a letra
s
ao nome da variável que armazena a matriz. Por exemplo:
const students = ['Eddie', 'Julia', 'Nathan', 'Theresa']
Values Valores lógicos
Os nomes de variáveis booleanas fazem sentido para começar com
is
ou
has
. Isso os aproxima das construções disponíveis em linguagem comum. Por exemplo, aqui está a pergunta: “Essa pessoa é professora?”. A resposta para isso pode ser "Sim" ou "Não". Você pode fazer o mesmo selecionando nomes para variáveis lógicas:
const isTeacher = true
▍ Parâmetros de funções passadas para métodos de matriz padrão
Aqui estão alguns métodos padrão de matriz JavaScript:
forEach
,
map
,
reduce
,
filter
. Eles permitem que você execute determinadas ações com matrizes. São funções passadas que descrevem operações em matrizes. Vi quantos programadores simplesmente passam parâmetros com nomes como
el
ou
element
para essas funções. Embora essa abordagem libere o programador de pensar em nomear esses parâmetros, é melhor chamá-los com base nos dados que aparecem neles. Por exemplo:
const cities = ['Berlin', 'San Francisco', 'Tel Aviv', 'Seoul'] cities.forEach(function(city) { ... })
▍ Identificadores
Muitas vezes acontece que um programador precisa trabalhar com os identificadores de determinados conjuntos ou objetos de dados. Se esses identificadores estiverem aninhados, nada de especial precisa ser feito com eles. Por exemplo, ao trabalhar com o MongoDB, costumo converter
_id
em
id
antes de retornar o objeto ao aplicativo front-end. Ao extrair identificadores de objetos, é recomendável formar seus nomes, definindo o tipo do objeto antes da
id
. Por exemplo:
const studentId = student.id
Uma exceção a esta regra está trabalhando com referências do MongoDB em modelos. Nesses casos, é recomendável nomear os campos de acordo com os modelos mencionados neles. Isso, ao preencher documentos para os quais existem links nos campos, permitirá manter o código limpo e uniforme:
const StudentSchema = new Schema({ teacher: { type: Schema.Types.ObjectId, ref: 'Teacher', required: true, }, name: String, ... })
10. Use a construção assíncrona / aguardada sempre que possível.
O uso de retornos de chamada diminui a legibilidade do código. Isso é especialmente verdadeiro para retornos de chamada aninhados. Promete corrigir as coisas um pouco, mas acredito que o código que usa a construção assíncrona / espera é melhor lido. Mesmo iniciantes e desenvolvedores que mudaram para JavaScript de outros idiomas podem entender facilmente esse código. A coisa mais importante aqui é dominar os conceitos subjacentes a assíncrono / espera. Não use esse design em qualquer lugar devido à sua novidade.
11. O procedimento para importar módulos
As recomendações 1 e 2 demonstraram a importância de escolher o local certo para armazenar o código para garantir que ele seja suportado. Idéias semelhantes se aplicam à ordem de importação dos módulos. Ou seja, estamos falando sobre o fato de que a ordem lógica da importação de módulos torna o código mais claro. Ao importar módulos, sigo o seguinte esquema simples:
Este exemplo é baseado em React. A mesma ideia não será difícil de transferir para qualquer outro ambiente de desenvolvimento.
12. Evite usar o console.log
O comando
console.log
é uma ferramenta simples, rápida e conveniente para depuração de programas. É claro que existem ferramentas mais avançadas desse tipo, mas acho que quase todos os programadores ainda usam o
console.log
. Se, usando o
console.log
para depuração, você não remover as chamadas desse comando que se tornam desnecessárias com o tempo, o console logo ficará completamente desordenado. Deve-se notar que faz sentido deixar algumas equipes de registro mesmo no código de projetos que estão completamente prontos para o trabalho. Por exemplo, comandos que exibem mensagens de erro e avisos.
Como resultado, podemos dizer que é bem possível usar o
console.log
para fins de depuração e, nos casos em que os comandos de log são planejados para serem usados em projetos de trabalho, faz sentido recorrer a bibliotecas especializadas. Entre eles estão o
nível de log e o
winston . Além disso, o ESLint pode ser usado para combater comandos de registro desnecessários. Isso permite uma pesquisa global e remoção de tais comandos.
Sumário
O autor deste material diz que tudo o que ele falou aqui o ajuda muito a manter a limpeza e a escalabilidade da base de código de seus projetos. Esperamos que você ache essas dicas úteis.
Caros leitores! O que você poderia adicionar às 12 dicas aqui para escrever código JS limpo e escalável?
