Qual o preço da pressa?

faicalcarvalho

Faiçal Carvalho

Posted on October 15, 2019

Qual o preço da pressa?

Legibilidade e estilo em JavaScript

Uma das principais características de um programa é a sua legibilidade.

Mas, o que é legibilidade?

No contexto da programação, a legibilidade é o grau de facilidade com que a gente consegue ler o programa. Ou seja, o quanto o programa é legível, de fácil entendimento.

Quem executa o programa é o computador. Para o computador, a forma como o programa está escrito não importa. O computador simplesmente não considera a legibilidade. É algo que ele ignora completamente. “Legibilidade é coisa de humanos”, ele deve pensar…

Então, porque estamos falando de legibilidade? A legibilidade tem importância? Se a legibilidade tem alguma importância, para quem ela é importante? Quem se importa com a legibilidade?

Os programas são escritos por nós, seres humanos, correto? (Na imensa maioria dos casos, sim, isso é verdade. Mas há também programas cuja execução resulta na geração de outros programas. Na área de testes de sistemas, acontece muito isso de um programa gerar um ou vários programas de teste... mas isso é outra história.)

Retomando: os programas são escritos por nós, seres humanos. É uma realidade. Mas é muito importante a gente ter presente uma realidade que vem na sequência dessa: além de escritos por nós, os programas precisam também ser lidos por nós. É aí então que entra a legibilidade.

Por qual motivo eles precisam ser lidos?

Nós temos de pensar o seguinte: Criar um programa é algo que ocorre só uma vez. Porém, na prática, todo programa, depois de criado, precisa ser mantido.

Porque ele precisa ser mantido? As principais causas são:

  • Para corrigir algum problema que tenha sido detectado (manutenção corretiva).
  • Para acrescentar uma nova funcionalidade (manutenção evolutiva).
  • Para adaptar o código a alguma mudança no ambiente externo – por exemplo, mudanças na legislação (manutenção adaptativa).

A necessidade de dar manutenção em um programa é MUITO mais frequente do que a de criar um programa do zero. Por essa razão, a facilidade com que um programa pode ser mantido – isto é, sua manutenibilidade – é superimportante.

Na hora de dar manutenção, a legibilidade é fundamental.

Frequentemente, quem programa costuma sofrer pressões – as empresas costumam ser implacáveis na cobrança por uma solução rápida. A pressa faz com que alguns cuidados – sobretudo os relacionados com a legibilidade – não sejam considerados.

Mais tarde, vêm as consequências.

Para alterar um trecho de código, você precisa saber o que está fazendo. Para isso, você precisa ler e entender – e é aí que a gente conclui que a legibilidade tem uma importância capital. Sem trocadilho.

Legibilidade === $$$

Se, na hora de dar manutenção, você demorar muito para entender o programa por falta de legibilidade, isso certamente vai implicar em custos para a empresa.

Vamos ver agora algumas características que configuram a legibilidade de um programa.

Nos exemplos de código que vamos mostrar, estamos usando uma forma similar à apresentada no livro “The Practice of Programming” (“A Prática da Programação”), de Kernighan e Pike. O código que consideramos inadequado ou questionável é precedido pelo comentário "// ???".

É bom esclarecer que algumas questões que afetam a legibilidade são questões de estilo. Entra nisso, em alguns casos, o gosto pessoal.

Em várias situações, no entanto, sobretudo para quem está começando a programar, o mais prudente é seguir atentamente as recomendações. Depois, com o tempo, aos poucos vão surgindo naturalmente as escolhas pessoais.

Espaços em branco

Vamos começar com o uso de espaços em branco no código. Isso influi muito na legibilidade. Compare esses dois trechos:

//  OK
seja clicouFora = (x < X1) || (y < Y1) || (x > X1 + DX) || (y > Y1 + DY)

//  ???
seja clicouFora=(x<X1)||(y<Y1)||(x>X1+DX)||(y>Y1+DY)

Mesmo sem saber do que trata o código acima, a primeira forma é bem mais clara, bem mais legível que a segunda.

Aqui vai uma primeira regra: Deixe sempre um espaço em branco em ambos os lados de todos os operadores binários (operadores que têm dois operandos, um de cada lado).

Isso vale para os operadores de atribuição:

//  OK
x = X1
x += X2 + ((x - X2) / 2)

//  ???
x=X1
x+=X2+((x-X2)/2)

Vale também para os operadores de comparação:

//  OK
se (x <= X1)
    x++

//  ???
se (x<=X1)
    x++

Para os operadores aritméticos:

//  OK
seja número = vabM * 4 / Mat.potência(vabM, 4) + Mat.potência(vabM, 4)
número = 1 - Mat.raiz(3 - 6 * número)

//  ???
seja número=vabM*4/Mat.potência(vabM,4)+Mat.potência(vabM,4)
número=1-Mat.raiz(3-6*número)

Para os operadores lógicos:

//  OK
se (x > X1 && x < X2 && y > Y1 && y < Y2)
    x++

//  ???
se (x>X1&&x<X2&&y>Y1&&y<Y2)
    x++

Vale também para o operador ternário:

//  OK
x = (x > X1 && x < X2) ? 1 : 0

//  ???
x=(x>X1&&x<X2)?1:0

No caso dos operadores unários, consideramos mais adequado não deixar um espaço em branco. Por exemplo, depois do operador ! (negação):

//  OK
se (!iniciou)
    iniciar()

//  ???
se (! iniciou)
    iniciar()

Da mesma forma, operadores de incremento ++ ou decremento -- também não devem ter um branco entre eles e o operando:

//  OK
n++

//  ???
n ++

O espaço em branco é importante também no uso dos comandos. Deixe sempre um espaço em branco após a palavra chave dos comandos:

//  OK
se (a > b)
    b++

//  ???
se(a > b)
    b++

//  OK
enquanto (a > b)
    b++

//  ???
enquanto(a > b)
    b++

//  OK
para (i = 0; i < tam; i++)
    lista[i] = nulo

//  ???
para(i = 0; i < tam; i++)
    lista[i] = nulo

Mudanças de linha

A mudança de linha é outro aspecto que influi muito na legibilidade. Muitos comandos possuem um ou mais comandos subordinados. Eles devem ser posicionados na próxima linha:

//  OK
se (a > b)
    b++

//  ???
se (a > b) b++

//  OK
enquanto (a > b)
    b++

//  ???
enquanto (a > b) b++

//  OK
para (i = 0; i < tam; i++)
    lista[i] = nulo

//  ???
para (i = 0; i < tam; i++) lista[i] = nulo

Indentação

A indentação é a forma de posicionar os comandos nas linhas, sobretudo considerando a distância em relação à margem esquerda e a subordinação entre comandos. Sem que tenhamos mencionado, quase todos os exemplos que temos dado incluem aspectos relacionados com a indentação.

Nós adotamos a indentação com 4 caracteres. Isto significa que os níveis de tabulação do código avançam de 4 em 4 caracteres.

É muito comum você encontrar código em JavaScript adotando indentação com 2 caracteres. Nós preferimos 4.

Conforme você já deve ter observado, o comando subordinado deve ser posicionado com um nível a mais de indentação:

//  OK
se (a > b)
    enquanto (b < c)
        b++

//  ???
se (a > b)
enquanto (b < c)
b++

Indentação na declaração de uma função

Na declaração de uma função você deve também estar atento a alguns detalhes importantes:

  • A palavra função e o nome da função devem ser colocados na mesma linha, separados por um espaço em branco.
  • Entre o nome da função e o abre parêntese da lista de parâmetros não deve haver um espaço em branco.
  • Os parâmetros entre parênteses devem estar separados por vírgula, cada uma seguida de um espaço em branco.
  • Entre o último parâmetro e o fecha parêntese não deve haver um espaço em branco.
  • Entre o fecha parêntese da lista de parâmetros e o abre chave do bloco de comandos da função deve ser colocado um espaço em branco.
  • Os comandos da função devem ser posicionados um nível de indentação acima do que está a palavra função.
  • O caractere fecha chave ao final da função deve ficar numa linha isolada, e deve ser posicionado no mesmo nível de indentação da palavra função.

O exemplo abaixo ilustra todos esses aspectos.

//  OK
função comparar(a, b) {
    retornar a - b
}

//  ???
função comparar ( a, b ) {
    retornar a - b
}

Chamada a uma função

Na chamada a uma função, não deve haver um espaço em branco entre o nome da função e o abre parêntese:

//  OK
seja result = comparar(x, y)

//  ???
seja result = comparar (x, y)

//  ???
seja result = comparar( x, y )

//  ???
seja result = comparar ( x, y )

Na lista de argumentos usados na chamada, que aparece obrigatoriamente entre parênteses, não deve haver um espaço em branco após o abre parêntese nem antes do fecha parêntese.

Posicionamento das chaves

De uma maneira geral, as chaves que delimitam blocos de comandos devem seguir o mesmo modelo que usamos no bloco de comandos de uma função, isto é, o abre chave na mesma linha do início do comando, e o fecha chave numa linha isolada. Assim, por exemplo, para um comando se:

//  OK
se (a > b) {
    a++
    b++
}

//  ???
se (a > b) {
    a++
    b++
    }

//  ???
se (a > b)
{
    a++
    b++
}

Isso vale para todos os comandos.

Use o bloco (abre/fecha chaves) somente se necessário

Quando o comando subordinado é constituído de apenas um comando, não use as chaves que delimitam um bloco. Por exemplo:

//  OK
se (a > b)
    a++
senão
    b++

//  ???
se (a > b) {
    a++
} senão {
    b++
}

Esta é outra recomendação polêmica. Muitos preferem sempre usar as chaves, independentemente do número de comandos. Nós não. Se na parte subordinada há apenas um comando, o bloco entre chaves não deve ser usado.

O exemplo abaixo ilustra isso.

//  OK
se (c === '*' || c === '/')
    op = MULT
senão
    op = SOMA
senão
    opInválido(c)

//  ???
se (c === '*' || c === '/') {
    op = MULT
} senão {
    op = SOMA
} senão {
    opInválido(c)
}

Indentação do comando se com cláusula senão

A indentação do comando se com a cláusula senão também apresenta algumas peculiaridades. Sua forma mais simples é a seguinte:

Comando se com a cláusula senão em JavaScript

Para os casos em que há múltiplas cláusulas senão seguidas, a forma mais adequada é a seguinte:

Comando se com múltiplas cláusulas senão em JavaScript

Indentação do comando escolher

O comando escolher possui características especiais em sua indentação. Indicamos a seguinte:

O comando escolher em JavaScript

Algumas variações são bem razoáveis. Por exemplo, a de alinhar a indentação dos casos no mesmo nível do comando escolher:

O comando escolher em JavaScript com indentação no mesmo nível do comando

É importante observar que os comandos dentro de cada caso sempre ficam alinhados um nível a mais que as palavras caso. Também como mostram os exemplos acima, indicamos colocar uma linha em branco entre os casos.

Nomes

Conforme já vimos em outro vídeo/post, dar um nome aos itens que compõem um programa é algo que deve ser feito com muito cuidado e atenção.

Veremos a seguir algumas regras que consideramos como critérios que devem ser levados em conta nesse aspecto.

O tamanho do nome depende do contexto

Nomes de coisas exportadas devem ser mais descritivos. Nomes locais devem ser pequenos.

Você pode, por exemplo, exportar funções e variáveis com nomes como:

  • exibirMapa
  • inserirElemento
  • alterarPerfilDeUsuário
  • numClientes
  • suprimirConta
  • maxQtdLivros
  • ModeloPadrão

Portanto, são nomes mais descritivos. Mas, não é conveniente exagerar. Aqui estão alguns nomes que certamente poderiam ser melhorados:

  • númeroDeAlunosAbaixoDaMédia
  • ElementoDaInterfaceGráficaDeUsuário
  • notaMínimaParaPassarDeAno

Para uma variável de controle de um loop, a melhor escolha é quase sempre i. Se, por algum motivo, não puder ser i, que seja j, k ou ind ou algo similar, com poucos caracteres.

No trecho a seguir, inspirado no livro já citado “The Practice of Programming” (“A Prática da Programação”) de Kernighan e Pike, você vê um exemplo que demonstra claramente a vantagem do uso de variáveis locais com nomes pequenos:

Dois exemplos do uso de variáveis de controle. O primeiro utiliza nomes pequenos, conforme indicado, e o segundo nomes grandes.

Compare os dois trechos acima e veja qual você considera o mais legível.

Propriedades de um objeto não devem repetir o nome do objeto

Como as propriedades de um objeto são geralmente referenciadas por meio de uma variável que representa o objeto, não é necessário que elas também contenham, em seus nomes, outra referência ao próprio objeto. Exemplo:

Declaração de dois objetos em JavaScript. A primeira com o nome de propriedades sem repetir o nome do objeto. A segunda repetindo o nome do objeto no nome das propriedades.

Algumas convenções

Nome de funções construtoras devem ter a primeira letra em maiúscula. Quando houver mais de um termo, cada um também deve ter a sua inicial em maiúscula. Exemplos:

  • Lista
  • Usuário
  • ElementoGráfico

Nome de variáveis, de funções (não usadas como construtoras) e de parâmetros de funções devem ter a primeira letra em minúscula. Quando houver mais de um termo, cada um deve ter a sua inicial em maiúscula. Exemplos:

  • i
  • temp
  • pesquisarControles
  • últimoElemento
  • conectarPontosOpostos

É também usual a convenção de usar nomes de constantes com todas as letras em maiúsculas:

Declaração de constantes em JavaScript utilizando letras maiúsculas nos nomes.

Esta é uma tradição herdada da linguagem C. Apesar de antiga, é uma convenção que contribui com a legibilidade.

💖 💪 🙅 🚩
faicalcarvalho
Faiçal Carvalho

Posted on October 15, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Qual o preço da pressa?
javascript Qual o preço da pressa?

October 15, 2019