Não crie seus códigos para que somente Deus entenda

Quando aprendemos a programar, somos guiados pelas orientações de professores, de algum tutorial que vimos na internet, ou por algum livro, onde vemos inúmeras rotinas, algumas pequenas e outras um pouco mais compridas, variando em sua complexidade, mas geralmente são coisas básicas e simples, onde tudo é fácil de entender e funciona.

Mas a prática do dia a dia nos impõe desafios, e um deles é o prazo, que sempre é curto demais, principalmente quando não é pensado no caso de algo dar errado.

E nesse desafio de entregar no prazo (ou não estourá-lo demais), acabamos tornando nosso código mais “prático”. É nesse momento que começamos a errar.

Não se trata de errar no sentido do sistema não funcionar ou algo assim, é no sentido que criamos algo que só sabemos enquanto estamos naquele projeto, passado algum tempo (não necessariamente longo) e voltamos a esse projeto, seja para implementar alguma funcionalidade, seja para tentar aproveitar algo em outro sistema, nos vemos diante de um antigo escrito persa, que ninguém entende facilmente, e somente depois de muitas horas é que pegamos o “espirito” de como o sistema funciona.

Listagem 1: Uso de variável sem nome significativo.

foreach ($_SESSION['c'] as $k=>$v):

Vendo essa linha, dá para saber o que é feito, ou a que se refere?

Alguns mais experientes dirão que c é um array e estamos pegando seus valores.Ok, mas o que é k e v?Somente pela linha não é possível dizer exatamente o que são, mas provavelmente é algo no esquema chave/valor, afinal, estamos trabalhando com um array.

Aparentemente isso é simples, mas imagine uma plataforma de e-commerce com vários arrays, nomeados dessa forma e referenciados em diversas partes dessa plataforma, até achar onde é criada a array, e o que é armazenado nela, já gastamos um certo tempo nisso, e para descobrir onde está o causador do erro misterioso com tantos c, k, v, b, f... ?

E se aquela linha fosse escrita assim:

Listagem 2: Variáveis renomeadas.

foreach ($_SESSION['carrinho'] as $id=>$value):

Já ficou mais claro, correto?

Muitas vezes, falamos sobre as boas práticas, mas parece algo etéreo, tão distante quanto parnaso, com exemplos abstratos e muita teoria, mas a verdade, é que as boas práticas no código é igual a manter a mesa de trabalho em ordem.

Geralmente temos na mesa um bloco de anotações, alguns papeis, livro para consulta rápida, canetas, e um monte de coisa que poderia muito bem não estar ali.

O mesmo se aplica ao código que fazemos, é preciso deixar somente o essencial e que tenha nomes claros e objetivos, que já diga para que serve sem precisar de comentários ou de aulas sobre vidência.

Por exemplo, encontramos aberrações como nomear variáveis como var1, var2, var3 …. porque não var_login, var_senha, var_imagem …. ?

O uso de funções é outro item que devemos deixar claro, seja para o fácil entendimento quando lemos, seja para sabermos onde está aquilo que desejamos utilizar num outro projeto, e com isso ganhamos tempo e agilidade.

Listagem 3: Funções de nome não significativo.

$02=001();

$i = fill( <parâmetros>)

Dois exemplos de funções obscuras, a primeira por ser numérica, não sabemos ao que se refere, teríamos de descobrir onde está essa função e o que ela faz. A segunda, parece que é algo com preenchimento de uma imagem ou desenho, talvez, mas e se disser que na verdade é uma função de recorte e preenchimento com a cor passada pelo usuário?

Listagem 4: Funções renomeadas.

$db=conectar_db();

$image = resize_fill( <parâmetros>)

Assim fica mais claro, não?

Ao procurar por boas práticas e código bem escrito, vemos coisas como escrever pensando em outros programadores que podem, no futuro, ter acesso ao código escrito por nós, seja para dar manutenção, seja para implementar algo.

Mas por diversas razões egoístas, muitos desenvolvedores preferem escrever códigos obscuros, numa tentativa de amarrar o cliente, para que nenhum outro concorrente, possa dar o suporte necessário no tempo desejado, mas além disso ser algo que demonstra claramente a falta de maturidade profissional, é uma punhalada nas costas de si mesmo. Porque?

Simples, muitas vezes, o cliente retorna para pedir uma alteração ou implementação, passado um bom tempo, as vezes alguns anos, e ao abrir o código, nos deparamos com algo que sequer identificamos como sendo nosso, afinal evoluímos como programadores, e o código que escrevemos atualmente é muito diferente daquele que escrevemos há um ano atrás, se não seguimos nenhuma boa prática.

E é nesse ponto que se morre pela boca, com medo da concorrência, obscureceu o código, e agora precisa primeiro decifrar o que está escrito, para depois fazer o que foi solicitado, e com isso, vai gastar no mínimo, um terço a mais de tempo do que havia inicialmente planejado e se comprometido com o cliente.

Se tivesse escrito um código de forma clara, limpa e coesa, sem medo da concorrência, ou de qualquer outro motivo, daria para entregar no prazo estimado e manter o cliente satisfeito com seu serviço.

As vezes vemos algumas pessoas perguntando se é melhor escrever em camel case, em inglês, ou perguntando o que os outros desenvolvedores praticam.

Antes de qualquer coisa, o código deve ser escrito de forma que possa ser lido por seres humanos. Além disso, deve ser feito pensando na capacidade de manutenção do código. Assim, devemos estruturar o código de forma que possa ser compilado (entendido por máquinas) e ser lido por qualquer desenvolvedor (incluindo nós mesmos) seja durante a criação do projeto, seja depois de entregue.

Existem alguns princípios que nos guiam nessa prática de escrever códigos legíveis a qualquer um (inclusive nós mesmos).

Princípios como KISS (Keep It Simple, Stupid!) que defende em manter tudo o mais simples possível; ou o SOLID que abrange 5 conceitos que são:

  • Princípio da Responsabilidade Única: um objeto deve possuir uma única responsabilidade.
  • Princípio Aberto / Fechado: O sistema deve ser aberto para extensão, mas fechado para modificação.
  • Princípio da Substituição de Liskov: Objetos devem ser substituídos por instâncias de seus subtipos, sem afetar a correção do programa.
  • Princípio de Segregação da Interface: Muitas interfaces específicas são melhores do que uma interface de uso geral.
  • Princípio de Inversão da Dependência: Deve-se depender de interfaces abstratas e não de classes concretas, uma vez que implementações concretas são mais propensas a mudanças.

Outras recomendações que obtemos ao pesquisar ou ao ler um livro sobre o assunto são:

Use nomes que revelam seu propósito: Ao nomearmos uma variável, função, classe, etc.., devemos deixar claro ao que se destina a variável, por exemplo; String n; //nome do usuário; ficará melhor se nomeado: String nome_do_usuario;

Evite Informações Erradas: quando nomearmos nossas variáveis, funções, etc... não nomear de forma que possam causar mal entendidos ou com nomes parecidos que gerem confusão;

Faça Distinções Significativas: não nomearmos de forma enigmática, como a1, a2, a3... pois ninguém, nem o próprio autor saberá do que se trata passado algum tempo sem contato com esse projeto.

Cabe aqui também o clássico for i > n …. Nomeie de forma que basta ler a linha em si para já sabermos do que se trata; conecta_db ao invés de a1; nome_usuario em vez de a2 e assim sucessivamente e recorrentemente, façamos disso um hábito, algo tão natural quanto respirar, pois além de ser mais fácil para entendermos, é uma economia imensa de tempo (e por consequência de dinheiro), pois assim, basta uma leitura rápida e já saberemos do que se trata aquela variável ou função.

Use Nomes Pronunciáveis: não tem coisa mais complicada de pensar, dizer ou memorizar do que um nome impronunciável, como Function hndlimghght, mas se fosse um Function Manipula_tamanho_imagem, milhares de vezes mais fácil de memorizar, dizer para o colega do lado e de procurar no meio de centenas ou milhares de linhas de código.

Use Nomes Passíveis de Busca: nomes que são uma única letra, numero, ou consoantes agrupadas são passiveis de não serem facilmente encontradas seja por ser muito comum, como a, b, c, 1, 2, 3 ...

Quantas centenas de vezes uma letra aparece num código e não é a função que estamos procurando? Ou no caso de sequências consonantais onde pode-se facilmente confundir um wv com um vw ou mn com nm ?Fatores como qualidade da imagem, cansaço do programador, dificuldade de visão, entre outros, podem fazer com que se perca um tempo precioso numa procura infrutífera por conta de uma letra que foi digitada por engano.

Evite Codificações: não crie código. Somos programadores, não um criptólogos. Ao desenvolver uma aplicação, um sistema, o que for, é necessário fazê-lo de forma que seja possível entender a qualquer tempo, seja no decorrer do desenvolvimento, seja daqui um bom tempo.

Desenvolver criando códigos para que ninguém além do próprio autor entenda, só serve para gastar um tempo desnecessário tentando decifrá-lo. Além de serem difíceis de serem pronunciados, é muito fácil de serem escritos de forma incorreta.

Evite o Mapeamento Mental: ao escrevermos um sistema, devemos fazê-lo de forma simples e fluida, facilitando assim nosso trabalho. Desenvolver algo onde é preciso anotar mentalmente ou no bloco ao lado para que serve ou significa cada função criada, é um contra-senso e extremamente anti-produtivo.

Faça apenas uma coisa: os métodos devem fazer uma coisa e devem fazê-la bem. O motivo de criarmos uma função é para decompor um conceito maior em uma série de passos no próximo nível de abstração.

Código inútil: todo código que não está sendo utilizado deve ser descartado. Não há necessidade de se manter algo que não se necessita. Utilize o controle de versão se necessitar lembrar de um código que foi apagado. Manter fantasmas no código só aumenta sua complexidade.

As classes devem ser pequenas: assim como métodos ou funções, a primeira regra para classes é que devem ser pequenas. A segunda é que devem ser menores ainda. A classe deve possuir poucas responsabilidades. O nome da classe deve descrever suas responsabilidades.

Se não derivamos um nome conciso e não ambíguo para ela, então provavelmente possui muitas responsabilidades. O principio da Responsabilidade única afirma que uma classe ou módulo deve ter um, e apenas um, motivo para mudar.

Coesão: coesão representa o quão uma classe é específica para desempenhar um papel em um contexto. As classes devem ter um pequeno número de instâncias de variáveis ou poucos colaboradores.

Quando temos uma classe coesa, os métodos e as variáveis da classe são co-dependentes e ficam juntas como um todo lógico.

Só o ato de dividir métodos grandes em menores causa a proliferação de classes. Digamos que tenhamos um grande método. Ao dividi-lo, iremos ter mais métodos e parâmetros sendo declarados e mais responsabilidade devido a separação das variáveis declaradas no contexto do método. Portanto, baixa coesão.

Entretanto, separar um função grande em muitas pequenas geralmente nos permite dividir várias classes também. Isso se dá por permitir melhor contextualizar e visualizar responsabilidades de seus métodos para novas classes.

Comentários: comentário servem para explicar seu código. Entretanto, não escreva comentários para explicar um código ruim, reescreva-o. Não amontoemos um módulo com comentários dogmáticos e supérfluos. Nada é tão prejudicial quanto um velho comentário mal feito que dissemina mentiras e informações incorretas. O uso de comentários é normalmente para compensar nosso fracasso em expressar a intenção do código em si.

Por que comentários são RUINS? - Porque eles mentem. Nem sempre, e não intencionalmente, mas é muito comum. Quanto mais antigo o comentário e mais longe do código o qual ele descreve, mais provável será que esteja errado.

Como podem notar, não é algo tão complexo ou difícil de se fazer, é algo simples e que basta começar a fazer que facilmente pegamos o hábito e o gosto de desenvolver seguindo essas práticas.

Elas são boas pois facilitam nossa vida, tornando nosso trabalho mais simples, permitindo que fiquemos focados naquilo que realmente importa que é desenvolver o aplicativo, ganharmos tempo, e por consequência, ganharmos dinheiro.