Desde que descobri minha paixão pela web, eu gosto muito de programar. Essa habilidade de transformar código-fonte em algo totalmente novo, que ajuda a resolver problemas reais de diversos usuários, sempre me motivou. Então, essa foi uma das razões que me fizeram ingressar numa faculdade. Queria muito trabalhar com programação para web.
Tinha a certeza que programar era apenas sobre escrever código e sobre fazer o computador interpretar as instruções: lógica, ponto e vírgula, classe e sintaxe. Mas logo descobri que é muito mais do que isso.
Enquanto estudava PHP e MySQL, utilizando alguns livros emprestados da biblioteca, eu fazia alguns “freelas” criando sites para uma agência de publicidade. Surgiu a oportunidade de estagiar em uma ótima empresa de desenvolvimento de software. Era uma oportunidade única! Trabalhar com várias pessoas em torno de um mesmo projeto. Tive que aceitar. A partir daí minha percepção começou a mudar.
Logo de cara, me deparei com diversas novidades. Aprendi uma nova linguagem, entendi como versionar usando git, e vi na prática o trabalho em equipe acontecendo: todos os devs juntando suas alterações em torno de um repositório. Como era de se esperar, algumas adversidades começaram a surgir.
O que esse trecho de código faz?
Cada pessoa tem uma forma de pensar, construir a solução de um problema, e também sua técnica preferida de nomear variáveis e métodos.
Um dos meus primeiros desafios foi entender o código alheio e também ter que explicar o meu código para outras pessoas. “O que esse trecho faz?” Pode ser uma pergunta muito comum, até mesmo quando se olha o código que você mesmo escreveu há algumas semanas.

Acabei aprendendo, de uma forma prática, que nenhum código é imutável. De alguma forma, um colega de equipe, ou você mesmo num futuro próximo, vai precisar modificar ou corrigir algum trecho do código-fonte. Então, quando mais evidente o que o código faz, melhor.
Uma dica bem importante é evitar nomes de variáveis e métodos como usr1 e sv_alt_bd ou afins. Uma simples “economia” de letras ou termos pode ofuscar a real intenção e funcionamento do código, gerando confusão. Prefira termos mais diretos como usuario e salvar_alteracoes ou apenas salvar.

Layout inconsistente e nomes confusos é um forte indício de que não há muita qualidade no código. Se o desenvolvedor não teve cuidado com essas questões relacionadas à apresentação, provavelmente não teve muita preocupação com questões mais vitais como, por exemplo, a aplicação de um bom design, um padrão de projeto ou testes mais abrangentes.
Tabulação ou Espaço?
Perguntas como “É melhor usar espaços ou tabulações?”; “Qual o melhor editor ou IDE?” ou “Qual a quantidade permitida de caracteres por linha?”. É desse tipo de assunto que surgem muitas discussões acaloradas pela internet afora. É o clássico Marvel vs DC do mundo da programação.
Por mais que cada desenvolvedor ou desenvolvedora tenha sua preferência é importante que algumas convenções sejam definidas para o projeto. Caso contrário, problemas vão começar a surgir.
No projeto que trabalhei durante meu estágio haviam alguns arquivos, mais antigos, que foram criados utilizando o GEdit. Nesse editor o padrão configurado era de 4 espaços para cada tabulação. Porém, nos arquivos mais recentes utilizamos um IDE, onde o padrão aplicado era de 2 espaços.
Um belo dia, enquanto alterava alguns métodos nos arquivos antigos eu tive a “brilhante” ideia de ajustar a tabulação de TODOS os arquivos modificados. A princípio, tudo estava indo de acordo com o planejado. Mas logo tive uma baita surpresa. Quando fui enviar meu código ao repositório principal, através de um pull request, deu conflito!
Enquanto eu alterava a tabulação, alguns devs mais experientes estavam corrigindo um problema nos arquivos legados. Então, depois de algumas horas corrigindo os merges manualmente, tudo voltou a funcionar.
Eu sei que esse exemplo é extremo, mas às vezes um pequeno detalhe, como adicionar uma linha em branco, um espaço a mais ou a menos, pode ser motivo de conflito e até mesmo gerar um problema de entendimento.

No exemplo acima você pode perceber que a intenção é que o método sair()
seja chamado apenas se a condição do IF não for OK. Mas, ao remover as chaves, o código Javascript esconde o verdadeiro comportamento: o interpretador sempre executará o sair()
. De modo geral, a apresentação tornou o código suscetível a erros.
Então, um pouco de convenção não faz mal ao projeto. Além de resolver os problemas que mencionei, garante que o sistema de controle de versão funcione da melhor forma possível, evitando assim conflitos desnecessários.
Recomendo fortemente o uso de linters para tornar seu código melhor e também mais aderente aos padrões empregados pela comunidade da tecnologia em que você está desenvolvendo. Com isso, além de tornar o código mais padronizado, será muito mais fácil novas pessoas contribuírem com o projeto.
Tem código demais aqui
Depois de alguns anos trabalhando com desenvolvimento comecei a identificar algum padrão nos bugs, que sempre se repetiam.
Acho que todo programador já teve orgulho daquele código complexo e extenso, composto de várias linhas, horas a fio de estudo e muita tentativa e erro. É quase uma obra de arte abstrata.
No caso, o símbolo de um dos projetos que estava trabalhando era uma imponente classe responsável por gerar e compactar arquivos de faturamento. Inúmeras regras de negócio, divididas em vários métodos no decorrer de centenas de linhas. Com certeza, era algo impressionante.
Inicialmente, essa classe foi criada por um dos desenvolvedores mais experientes do projeto. Mas quando as alterações começaram a surgir, todos acabaram contribuindo de alguma forma. A classe foi ganhando novas habilidades e os bugs começaram a surgir.
Com tantas linhas e tantas regras era muito difícil certificar-se de que todas as condições estavam corretas. Então, algo sempre acabava escapando. E era justamente ali que acabava gerando o mau funcionamento.
Aos poucos, dividindo esse arranha-céu multiuso do faturamento em classes menores, os bugs acabaram desaparecendo. Nessa época, aprendi conceitos valiosos que até hoje me ajudam a criar um código melhor. E posso afirmar com toda certa: quando você olhar para uma classe ou arquivo e pensar “Tem código demais aqui” provavelmente você está certo.
Uma das coisas que mais inflam o código de um projeto é a agregação de múltiplas responsabilidades a uma única classe. Para resolver esse problema podemos aplicar os princípios SOLID. Esses cinco princípios de desenvolvimento são diretivas, quando aplicados, ajudam a criar um software para que seja mais fácil de escalar e manter. Eles se tornaram populares graças a Robert C. Martin. Em uma próxima oportunidade, podemos falar detalhadamente sobre cada um dos princípios. Nesse momento vou focar apenas no primeiro deles.
De acordo com o princípio da responsabilidade única, ou em inglês Single Responsibility, como o próprio nome sugere, cada classe deve possuir apenas uma única responsabilidade. Imagine que você criou em seu sistema uma entidade chamada Nota Fiscal, responsável por armazenar as informações no banco de dados, gerar o arquivo PDF da nota e enviá-la por e-mail para o cliente. As chances de bugs surgirem nessa parte do código são extremamente altas. Sem contar que os testes unitários se tornam praticamente inviáveis.
Agora, em um design mais sustentável, onde cada responsabilidade fosse atribuída a uma classe especialista, tudo seria mais fácil de alterar e manter.
Os acumuladores de código-fonte
Escrever bastante código não significa criar bastante software. Logo, não podemos medir o progresso de uma tarefa com base na quantidade de linhas de código-fonte escritas em um dia.
Um código extenso, além de difícil compreensão, aumenta o esforço e o custo necessários para realizar modificações. Esse tipo de problema tem vários disfarces: trechos de códigos não utilizados, comentários sem propósito, verbosidade desnecessária e assim por diante. Vamos dar uma olhada nesse exemplo.

Muitos desenvolvedores, podem até achar que isso torna o código mais “descritivo”, porém o resultado é justamente o contrário - mais código significa mais coisas para ler e para entender. Então, nossos programas se tornam mais difíceis de serem compreendidos, o que pode torná-lo um ambiente favorável para os bugs se esconderem. Veja como podemos refatorar o exemplo anterior e torná-lo mais sucinto, resolvendo tudo em uma única linha:

A duplicação desnecessária é outro problema muito comum. Eu já presenciei, e já dupliquei código, até mesmo de forma não intencional. A principal causa desse perverso crime contra o código-fonte é o recurso de copiar e colar durante a programação. Às vezes por ingenuidade, ou preguiça de refatorar, um programador acaba copiando fisicamente uma função de uma classe para outra. Tudo isso se agrava quando o código ainda ganha sutis alterações.
Quando um código é duplicado, você ignora a repetição, e todos os bugs existentes são replicados. Mesmo que você corrija uma instância desse código, haverá uma fila de bugs idênticos prontos para te incomodar por mais alguns dias.
Não há nada melhor do que fazer uma bela limpeza e tornar o código mais leve e renovado.
Não se repita!
Em um dos projetos que trabalhei havia um padrão a ser seguido para relatórios em PDF, com logotipo, dados da empresa e algumas informações sobre o sistema. Mas no decorrer dos anos esse padrão foi evoluindo e se tornou até mesmo parametrizado via sistema. Mas, dezenas de relatórios tinham métodos replicados, melhorados em algum dos casos e até pequenas diferenças visuais. A solução definitiva foi refatorar todos os relatórios e criar uma classe responsável por desenhar o layout base do PDF, que deveria ser aplicada a todos os relatórios. Assim, removendo dezenas de linhas desnecessárias.
Esse conceito é comumente conhecido como DRY: Don’t Repeat Yourself! (Não se repita). O objetivo é ter um código enxuto, sem redundâncias desnecessárias. Muitos frameworks, como o Rails ou Spring acabam aplicando-o, através da convenção sobre configuração, como forma de tornar o desenvolvimento mais produtivo e menos suscetível a erros.
Nem sempre a duplicação de código acontece de uma forma intencional. Ela pode ocorrer por alguém reinventando a roda, pois não sabia que uma determinada função existia. Até mesmo pode acontecer pela criação de um recurso do zero, quando há uma biblioteca de terceiros amplamente aceita e testada que já resolve o problema. Usar bibliotecas comuns ajudam você a economizar tempo e esforço e, de quebra, protegem seu código de uma infinidade de falhas potenciais, já tratadas previamente pela comunidade.
Sem comentários!
Um bom código não precisa de pilhas de comentários para explicar seu funcionamento. Uma escolha cuidadosa de nomes de variáveis, funções e classes deixam o seu código muito mais expressivo, e literalmente, dispensa qualquer explicação adicional.
Comentários redundantes devem ser evitados a todo custo, pois servem apenas para ocupar espaço e tirar o foco do que é essencial no código-fonte.

Uma forma bem comum de aplicação desse recurso é a remoção de trechos de códigos que não são mais necessários. Não faça isso! É forte indício de que alguém não teve a coragem suficiente para remover esse trecho de forma definitiva, ou que estava testando algo e achou que poderia ser necessário habilitar o código novamente. A melhor solução é remover o código completamente. Utilizando o controle de versão é sempre possível resgatar qualquer alteração.
Refatore sem medo!
Um código desnecessário, ou mal construído, nem sempre é resultado de erros de código ou de uma manutenção ruim. Às vezes, pode ser causado por falhas de design no mais alto nível.
Ao longo do tempo, algumas classes e funções podem mudar seu propósito original para algo bem diferente, deixando enormes trechos de código não utilizados. Quando isso ocorrer, não tenha medo de fazer uma faxina. Substitua a estrutura antiga por uma nova e mais simples. Faça tudo o que for necessário para manter o código em dia.
Uma coisa que aprendi é que o design deve considerar a utilização de bibliotecas externas, que resolvam os seus problemas. O uso dessas bibliotecas eliminará a necessidade de escrever muito código desnecessário e facilitará a criação de testes. Um motivo extra, é que as bibliotecas mais populares provavelmente são robustas, extensíveis e bastante utilizadas.
Já que diversas questões essenciais já foram colocadas à prova por diversos desenvolvedores, seu código será mais seguro.
De modo geral, deixe seu código um pouco melhor a cada dia. Elimine a redundância e a duplicação à medida que encontrá-las.
Apenas atente-se a uma regra simples: faça as mudanças de refatoração separadas de outras mudanças funcionais. Isso garante que tudo que aconteceu fique evidente em seu sistema de controle de versões. Caso você não respeite essa regra, se houver um bug será mais difícil de rastrear se ele ocorreu por causa de uma nova funcionalidade ou por uma melhoria estrutural.
Lembre-se que a refatoração refere-se a uma mudança feita na estrutura de um código existente e que não altera seu comportamento. Uma melhoria, que altere o modo como o programa funciona não será uma refatoração.
Na minha máquina funciona!
Essa frase é tão comum no mundo da programação que virou até meme. Mas testes são um assunto muito sério. É claro que você deve rodar seu novo código para ver se ele funciona. Poucos programadores são tão autoconfiantes, e até um pouco arrogantes, para escrever e disponibilizar um código de alguma forma. Se atalhos forem tomados, o código raramente funcionará da primeira vez: problemas serão encontrados, seja pela equipe de Controle de qualidade ou até mesmo quando o cliente for usá-lo, o que é ainda pior.
Os testes manuais são trabalhosos e lentos. Para ser bem abrangente, vários passos individuais são necessários, os quais devem ser repetidos sempre que qualquer alteração for feita no código. Então, testes automatizados são o melhor caminho para garantir que tudo esteja correto, de uma forma eficiente e sem muito retrabalho. Como bônus, ainda temos uma documentação completa e sempre atualizada sobre o comportamento das classes e métodos de toda a aplicação.
Se possível, aplique o desenvolvimento orientado a testes (TDD). Essa é uma técnica importante para criar softwares melhores.
Faça commits atômicos
Controlar as versões do código é uma parte essencial do dia a dia do desenvolvimento. Sendo assim, os commits das alterações feitas no repositório narram a história do trabalho da equipe com o código. Analise a forma como você narra essa trajetória para que o histórico registrado seja de fácil compreensão.
Não acumule o trabalho de dias seguidos para realizar um commit. O ideal é que cada pequena modificação, separada por um propósito, resulte em um commit diferente. Afinal, quanto maior o bloco de código alterado, mais difícil será de identificar a real motivação da mudança realizada.
O código deve ser escrito para outras pessoas
E por último, podemos resumir tudo a uma grande lição: Escrevemos código para outras pessoas.
O código, após finalizado, será executado por um computador. O compilador, ou interpretador, estará sempre satisfeito em ler qualquer código antigo, ou mal construído, e transformá-lo em um programa executável, sem qualquer tipo de julgamento sobre a qualidade e organização do código-fonte.
Mas se o código não estiver construído de uma forma simples, e que revele as reais intenções, as pessoas serão induzidas ao erro enquanto a manutenção, o que resultará em bugs.
Assim como um texto, ele deve ser natural e fácil de ler. Afinal, a maior parte do processo de desenvolvimento consiste não em escrever instruções para o computador interpretá-las, mas em comunicar-se com as pessoas de sua equipe e interpretar os comportamentos desejados para a solução que estamos construindo.
Até a próxima!