Artigos

O que é código limpo e por que é essencial para desenvolver software de qualidade?

Muitos desenvolvedores já ouviram falar de código limpo ou até o utilizam todos os dias, às vezes sem saber muito sobre ele. Nesta publicação, explicaremos o que é código limpo, por que deve ser usado e por que é um bom hábito a incorporar. Se você já conhece código limpo, este artigo ajudará a revisar os conceitos principais; se a ideia é nova para você, ao terminar entenderá os benefícios de escrever código limpo e aprenderá como fazê-lo.

O que é código limpo?

Antes de aprofundar o assunto, precisamos mencionar Robert C. Martin (conhecido como Uncle Bob), um renomado engenheiro de software, coautor do Manifesto Ágil e colaborador no desenvolvimento dos princípios SOLID. Uncle Bob é o autor de Clean Code: A Handbook of Agile Software Craftsmanship, um livro muito influente que mudou a forma de escrever código.

Clean Code é um guia para escrever código elegante, eficiente e fácil de ler. Vamos abordar as diretrizes mais importantes, mas também recomendamos ler o livro, pois ele cobre mais temas e com maior profundidade do que podemos nesta publicação.

Nomes, comentários e formatação

Pode parecer trivial, mas nomes, comentários e formatação são aspectos importantes que permitem a qualquer desenvolvedor ler e compreender o código com mais facilidade.

Ao declarar novos atributos, funções ou métodos, o nome tem um papel essencial. Escolher um nome significativo que se explique por si só melhora nosso código. Devemos evitar nomes difíceis de ler, que não signifiquem nada ou não sejam relevantes para a finalidade do atributo, da função ou do método. Escolher o nome correto também facilita buscar e localizar esses nomes no código.

Se os nomes forem escolhidos corretamente, isso deve evitar a necessidade de comentários. Comentários devem ser evitados quando possível, pois podem ser prejudiciais se não forem usados adequadamente. São difíceis de manter porque, se o código muda, precisam ser atualizados manualmente. Se não forem atualizados, podem causar confusão e problemas desnecessários. Comentários informativos, legais ou esclarecedores podem ser feitos se ajudarem a tornar o código mais legível, mas, como regra geral, devem ser usados o mínimo possível. Se o código for limpo, não serão necessários.

Formatar o código pode parecer pouco importante, mas é um aspecto essencial para criar código profissional e legível. Os arquivos devem ter um número máximo de linhas de código, e cada arquivo não deve ultrapassar 500 linhas, se possível. Além disso, o código deve ter no máximo 100 a 120 caracteres na horizontal. Como é lido de cima para baixo e da esquerda para a direita, deve ser indentado conforme as convenções de ordem hierárquica.

Funções

Uma das regras mais importantes ao criar funções é mantê-las pequenas. Funções longas são difíceis de ler e entender, então devemos mantê-las simples e curtas. Se temos uma função com mais de 20 linhas de código, devemos tentar dividi-la em várias funções menores e mais fáceis de ler.

Outro aspecto essencial é que as funções devem fazer uma coisa só. Existem várias maneiras de saber se uma função faz apenas uma coisa, mas, como regra geral, se tem mais de um nível de abstração, faz mais de uma coisa. Devemos mantê-la em um único nível de abstração e evitar misturar níveis dentro da função.

Há muitos outros aspectos a considerar ao escrever funções, como o número de argumentos que devem usar. Ao planejar uma função, devemos ter em mente que não se deve usar mais de três argumentos. Idealmente, esse número deve ser o mais próximo possível de zero, pois isso reduz a complexidade das funções e facilita os testes. Menos argumentos significam menos testes, porque há menos combinações a testar. Por fim, as funções devem fazer o que se espera delas; isso pode parecer redundante, mas é importante garantir que usar uma função não cause efeitos colaterais indesejados ou comportamentos inesperados.

Objetos e estruturas de dados

Um aspecto essencial do código limpo é esconder a implementação atrás da abstração. Ao criar classes, devemos tentar esconder a implementação usando interfaces abstratas para evitar dependências entre seções do código. Usar métodos getter e setter para obter variáveis diretamente nas classes não é uma boa ideia. Interfaces devem ser usadas no lugar, permitindo manipular esses dados independentemente da implementação dessas classes. Isso evitará problemas desnecessários quando uma classe precisar de uma nova implementação.

Agora que escondemos nossa implementação, podemos cumprir a lei de Demeter. Essa lei afirma que os módulos não devem conhecer a estrutura interna dos objetos que manipulam. Como regra geral, os objetos devem expor comportamento e esconder dados; por outro lado, as estruturas de dados devem expor dados e não ter comportamento significativo.

Tratamento de erros e testes

A abordagem do código limpo para tratar erros envolve usar exceções para capturá-los em vez de retornar erros ou indicadores. Por exemplo, é uma boa prática usar try-catch nas seções do código que podem falhar e capturar os erros corretamente. Para depuração e melhor tratamento de erros, é importante criar mensagens de erro usadas pelas exceções, para que, quando um erro ocorrer, sejam fornecidas informações suficientes para identificar sua origem.

Os testes são uma parte importante do código limpo, e escrever testes adequados é essencial. Se possível, recomenda-se usar a técnica de programação TDD para garantir uma cobertura de testes de quase 100%. Os testes devem ser mantidos para que não sejam desenvolvidos separadamente do sistema. Se o código muda, o teste deve ser atualizado.

Ao escrever testes, há cinco regras que devemos seguir para garantir testes adequados e limpos: rápidos, isolados, repetíveis, que se autovalidem e oportunos (F.I.R.S.T). Como os testes devem ser executados continuamente durante a programação ou automaticamente depois de escrever o código, devem ser rápidos. Se forem lentos, os desenvolvedores podem evitar executá-los porque demoram demais. Isso leva a problemas futuros e más práticas.

Ao criar um teste, devemos lembrar que cada um precisa ser independente; nenhum deve depender de outro para ser executado. Os testes devem ser executados em todos os ambientes, como desenvolvimento ou produção. Se um teste roda em desenvolvimento, mas não pode rodar em produção, isso levará a más práticas. O resultado deve ser fácil de ler. A melhor prática é retornar um booleano indicando o resultado do teste, pois isso permitirá aos desenvolvedores obtê-lo rapidamente. Por fim, é uma boa prática planejar e escrever os testes antes de o código real chegar à produção.

Classes

Ao planejar e implementar classes, precisamos de uma abordagem semelhante à das funções. As classes devem ser pequenas, e é importante que o nome seja significativo, pois podem ser usadas em todo o sistema. Devem seguir o princípio da responsabilidade única (SRP). Para cumpri-lo, as classes devem ter apenas uma responsabilidade e apenas um motivo para mudar. Se uma classe tem muitas responsabilidades, uma boa prática é dividi-la em classes separadas.

Por que devemos usar código limpo?

Depois de discutir código limpo, podemos ver que há vários benefícios em usá-lo. Vamos revisar os benefícios mais importantes de aplicar seus princípios ao escrever código.

Custo

O custo de implementar um sistema pode ser uma questão essencial ao conseguir novos projetos ou clientes. É importante seguir as estimativas de custo para evitar problemas desnecessários com os clientes. Desenvolvedores ou gestores sabem que o custo de corrigir problemas ou bugs cresce exponencialmente à medida que o código avança pelas diferentes etapas de desenvolvimento. Seguir as práticas de código limpo ajudará a evitar esse problema por meio de testes unitários, testes criados seguindo F.I.R.S.T, uso de TDD etc.

Tempo

Pode ser difícil para os desenvolvedores lidar com projetos ou código que não escreveram ou dos quais não participaram. Imagine que você acaba de entrar em um projeto e precisa desenvolver uma nova funcionalidade ou corrigir um bug em um sistema. Se o código é difícil de ler, não há indentação e os nomes das classes ou métodos não significam nada, você terá de investir mais tempo do que o habitual para entender o código desse novo sistema. Se o código segue as diretrizes de código limpo, é fácil de ler, e os desenvolvedores levam menos tempo para entendê-lo, implementar novas funcionalidades ou corrigir bugs adequadamente.

Facilidade de manutenção

O processo de desenvolvimento não termina quando um sistema chega à produção. Precisamos investir uma quantidade significativa de tempo e esforço para mantê-lo atualizado e permitir que funcione corretamente e com eficiência. Se o código do sistema está desorganizado, teremos dificuldade para identificar quais seções precisam ser atualizadas ou quais dependências estão obsoletas.

Capacidade de adaptação

Os sistemas não são estáticos e, à medida que o negócio ou o contexto muda, precisam conseguir se adaptar a essas mudanças e continuar relevantes para os usuários. Precisamos garantir que o sistema construído possa mudar, pois a mudança é inevitável e devemos lidar com seu impacto. Se seguimos as diretrizes de código limpo sobre como implementar classes, estruturas de dados e objetos, evitamos trabalho desnecessário ao alterar ou atualizar seções inteiras do sistema.

Qualidade

Muitos dos aspectos mencionados acima determinarão se nosso sistema atende aos padrões de qualidade do desenvolvimento de software. Por isso, o código limpo se tornou um indicador de qualidade para os desenvolvedores: ajuda a desenvolver sistemas melhores.

Transformar o código limpo em um hábito

Vimos que usar práticas de código limpo beneficia sua forma de escrever código, mas como transformar essas diretrizes em um hábito e incorporá-las às suas habilidades? Primeiro, é preciso saber que não se domina código limpo em um dia: será necessário tempo para praticar e transformar esses conceitos em um hábito.

Como há muitos aspectos a considerar, recomendamos algumas dicas. Primeiro, faça uma pequena lista de todos os conceitos essenciais, como nomes, comentários, funções etc. Mantenha a lista por perto enquanto escreve código, para conferir os itens à medida que programa. Por exemplo, depois de escrever uma função, você pode verificar rapidamente seu nome, tamanho, se faz apenas uma coisa etc. Além disso, depois de criar uma pull request, pode revisar todo o código para verificar se segue essas diretrizes. Depois de um tempo, não precisará manter a lista por perto e começará a programar seguindo essas diretrizes sem precisar se lembrar delas.

Considerações finais

Na sophilabs, nós, desenvolvedores, usamos as diretrizes de código limpo para escrever nosso código diariamente. Esse é um dos aspectos essenciais que revisamos quando um desenvolvedor cria uma pull request. Pela nossa experiência, consideramos essas diretrizes a melhor maneira de escrever o melhor código possível. É bastante comum que novos desenvolvedores entrem na equipe. O processo de integração pode ser muito desafiador, pois precisam aprender como todos os sistemas funcionam. No entanto, o uso de código limpo permite entender o código o mais rápido possível e começar a entregar valor ao cliente mais cedo.

Escrever código não envolve apenas fazer algo que funcione e atenda às expectativas, mas fazê-lo da melhor maneira possível. Com código limpo, os desenvolvedores podem criar sistemas fáceis de manter, capazes de se adaptar às mudanças, que melhorem seu desempenho e evitem o desperdício de recursos. Incorporar código limpo como hábito é uma decisão que nos torna desenvolvedores melhores.

“O que é código limpo e por que é essencial para desenvolver software de qualidade?” por Facundo Revello está sob a licença CC BY SA. Os exemplos de código-fonte estão sob a licença MIT.

Foto de Émile Perron.

Classificado em Pesquisa e aprendizado.

Leituras relacionadas