No desenvolvimento de software, a clareza e a legibilidade do código são essenciais para garantir que ele seja fácil de entender, manter e evoluir. Um código de qualidade não é apenas aquele que funciona, mas também aquele que pode ser facilmente lido e compreendido por outros desenvolvedores, independentemente de sua familiaridade com o projeto. Entre os muitos princípios que contribuem para a criação de um código-limpo, a escolha de nomes significativos para variáveis, funções, métodos, classes e units é um dos mais fundamentais.
Nomes significativos são aqueles que comunicam claramente a intenção do código. Eles tornam o código autoexplicativo, reduzindo a necessidade de comentários adicionais e facilitando a navegação e a modificação. Em um ambiente de desenvolvimento onde várias pessoas colaboram no mesmo projeto, a utilização de nomes claros e descritivos pode fazer a diferença entre um código que é fácil de trabalhar e um código que é um pesadelo de manutenção.
Além disso, nomes significativos melhoram a produtividade dos desenvolvedores. Quando o código é fácil de entender, os desenvolvedores passam menos tempo tentando decifrar o que ele faz e mais tempo implementando novas funcionalidades ou corrigindo bugs. Isso se traduz em entregas mais rápidas e de maior qualidade.
Neste artigo, exploraremos em profundidade a importância dos nomes significativos no código-limpo. Discutiremos por que é crucial investir tempo e esforço na escolha de bons nomes e forneceremos exemplos práticos em Delphi para ilustrar como aplicar esse princípio de maneira eficaz.
Por que é importante um código-limpo?
Código-limpo é um conceito que se refere a escrever código que é fácil de ler, entender e modificar. As vantagens de manter um código-limpo incluem:
- Legibilidade: Código fácil de ler é mais fácil de entender. Isso é crucial quando diferentes desenvolvedores trabalham no mesmo projeto.
- Manutenção: Código claro reduz o tempo e esforço necessários para manutenção e refatoração.
- Colaboração: Facilita a colaboração entre desenvolvedores, pois todos podem rapidamente entender a lógica e o fluxo do código.
- Redução de Erros: Código claro e bem-estruturado é menos propenso a erros, pois é mais fácil identificar e corrigir problemas.
Os principais pilares
Os principais pilares do código-limpo são práticas e princípios que guiam os desenvolvedores na criação de código de alta qualidade. Cada pilar aborda um aspecto específico do desenvolvimento de software, contribuindo para a criação de um sistema que é fácil de entender, manter e evoluir. Aqui estão os principais pilares do código-limpo:
- Nomes Significativos: Usar nomes claros e descritivos para variáveis, funções, métodos, classes e units. Nomes significativos comunicam a intenção do código e facilitam a compreensão e navegação.
- Funções Pequenas e Focadas: Manter funções pequenas e focadas em uma única tarefa. Funções menores são mais fáceis de entender, testar e manter, além de promoverem a reutilização do código.
- Comentários Eficientes: Utilizar comentários para explicar o porquê das decisões de design e fornecer contexto adicional, em vez de explicar o que o código faz. Comentários eficientes complementam o código sem sobrecarregá-lo.
- Formatação Consistente: Manter uma formatação consistente no código para melhorar a legibilidade e facilitar a colaboração. Isso inclui seguir convenções de indentação, espaçamento e estilo de código.
- Tratamento Adequado de Erros: Implementar um tratamento de erros robusto e claro, utilizando exceções e fornecendo mensagens de erro informativas. Isso ajuda a garantir que o software se comporte de maneira previsível em situações de erro.
- Estrutura Coesa e Baixo Acoplamento: Projetar classes e módulos com responsabilidades bem definidas e reduzir as dependências entre eles. Isso torna o sistema mais modular, flexível e fácil de manter.
- Testes Automatizados: Escrever testes automatizados para verificar o comportamento do código e garantir que novas mudanças não introduzam regressões. Testes automatizados aumentam a confiança no código e facilitam a refatoração.
- Refatoração Contínua: Realizar refatorações contínuas para melhorar a clareza e a estrutura do código sem alterar seu comportamento. A refatoração contínua ajuda a manter a qualidade do código ao longo do tempo.
- Código Simples e Direto: Escrever código que seja o mais simples e direto possível, evitando complexidade desnecessária. Código simples é mais fácil de entender e manter.
- Princípios SOLID: Aplicar os princípios de design SOLID (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) para criar sistemas mais robustos e flexíveis.
Primeiro pilar: Nomes Significativos
Nesse primeiro artigo da série vamos abordar o pilar: Noms Significativos. Usar nomes significativos para variáveis, funções, métodos, classes e units é crucial para a legibilidade do código. Nomes bem escolhidos transmitem claramente o propósito e a funcionalidade de cada elemento, tornando o código autoexplicativo.
Por que é importante pensar antes de dar nomes às coisas?
- Clareza de Intenção: Nomes claros comunicam a intenção do código, facilitando a compreensão imediata do que cada parte do código faz.
- Redução de Comentários: Quando os nomes são significativos, a necessidade de comentários diminui, pois o código se explica por si mesmo.
- Facilidade de Navegação: Nomes bem escolhidos tornam mais fácil navegar pelo código e encontrar o que se precisa.
- Manutenção Facilitada: Bons nomes facilitam a manutenção, pois qualquer desenvolvedor pode rapidamente entender e modificar o código sem introduzir erros.
- Consistência: Pensar nos nomes ajuda a manter consistência no projeto, o que é essencial para a coesão do código.
10 Exemplos para aprendermos
Pra ficar mais claro vamos criar exemplos e demonstrar como fica tão mais fácil quando nos preocupamos em criar nomes melhores em todas as situações:
Variáveis
- Antes: Usar nomes de variáveis como
x
é confuso e não comunica a intenção da variável.
1 2 3 4 5 6 7 |
var x: Integer; begin x := 10; end; |
Depois: Usar um nome descritivo como idade
torna claro que a variável representa a idade.
1 2 3 4 5 6 7 |
var idade: Integer; begin idade := 10; end; |
Funções
- Antes: Funções com nomes genéricos como
Soma
não indicam claramente o que está sendo somado.
1 2 3 4 5 6 |
function Soma(a, b: Integer): Integer; begin Result := a + b; end; |
Depois: Um nome descritivo como SomarDoisNumeros
deixa claro que a função soma dois números.
1 2 3 4 5 6 |
function SomarDoisNumeros(numero1, numero2: Integer): Integer; begin Result := numero1 + numero2; end; |
Vamos imaginar algo mais próximo da sua realidade. Imagine uma função que calcula impostos. Pense:
1 2 3 |
function CalcImpsFed(A, B, C: Double): Double; |
Não está claro que são impostos Federais que estão sendo calculados, dá pra dar um chute, lógico, porém pra ter certeza o que programador terá que abrir a função e analisar.
1 2 3 |
function CalcularImpostosFederais(A, B, C: Double): Double; |
Agora fica muito mais claro que estamos calculando impostos federais no método, portanto não precisamos abrir a função pra termos certeza. Só os parâmetros que estão ruins, mas veremos isso ainda nesse artigo.
Métodos
- Antes: Métodos com nomes genéricos como
BtnClick
não indicam a ação específica que é realizada quando o botão é clicado.
1 2 3 4 5 6 |
procedure TForm1.BtnClick(Sender: TObject); begin // Código aqui end; |
Depois: Um nome descritivo como ExibirMensagemDeBoasVindas
deixa claro o propósito do método.
1 2 3 4 5 6 |
procedure TForm1.ExibirMensagemDeBoasVindas(Sender: TObject); begin ShowMessage('Bem-vindo!'); end; |
Nesse caso em específico, ao invés de codificarmos diretamente no OnClick do botão, transferimos a responsabilidade para uma procedure e colocamos um nome mais amigável, então chamaríamos esse novo método através do botão.
Classes
- Antes: Nomes de classes genéricos como
TCalc
não indicam a responsabilidade da classe.
1 2 3 4 5 |
type TCalc = class end; |
- Depois: Um nome descritivo como
TCalculadora
indica claramente que a classe é responsável por cálculos.
1 2 3 4 5 6 7 |
type TCalculadora = class public function Somar(a, b: Integer): Integer; end; |
Units
No caso de Units do sistema, você muito provavelmente utiliza-se de nomes curtos em seus software ou ainda nomes singulares, tais como: uCalc, uImpostos, uNotaFiscal
. Não são totalmente ruins, mas podemos melhorar isso ainda mais.
- Antes: Usar nomes de units genéricos como
uCalc
não fornece nenhuma informação sobre o conteúdo ou a responsabilidade da unit.
1 2 3 |
unit Unit1; |
Uma boa alternativa é organizar seus projetos em pastas e então gravar as units nas respectivas pastas com namespaces relacionados. Namespaces são interessantes pois facilmente conseguimos identificar que tipo de arquivo estamos lidando, imagine os nomes abaixo:
uViewCalcImposto.pas
uCalcImposto.pas
Só conseguimos saber que a primeira Unit é de um form onde vamos calcular os impostos devido ao nome “View” que compoe o nome. Agora imagine que cada um dessas units esteja salva em uma pasta diferente, assim: A unit “uViewCacImposto” está salva em Views e “uCalcImposto.pas” esteja salva na pasta Bibliotecas. E imagine também que nosso projeto chama-se “SuperCalc.exe”.
Poderíamos melhorar isso dandos os seguintes nomes às units:
SuperCalc.Views.ViewCacImposto.pas
SuperCalc.Bibliotecas.CalcImposto.pas
Isso já melhora significativamente o entendimento. Mas ainda podemos melhorar. Os nomes poderiam sem mais autoexplicativos ainda.
SuperCalc.Views.ViewCaculaImpostos.Federais.pas
SuperCalc.Bibliotecas.CalculaImpostos.Federais.pas
Pronto! Sei que você vai me diser: “Puxa, estão longos os nomes”. Melhor longos do que “não autoexplicativos”. Dessa forma conseguirmos saber que tanto a unit do form quanto a bibliteca referem-se a cáculos de impostos federais. Se mais tarce precisamos de impostos estaduais, já imagina como faremos correto?
Constantes
Nomes de constantes são os que a maioria dos desenvolvedores mais pecam. Creio que você não seja radical a ponto de usar uma única letra como o exemplo abaixo:
- Antes: Usar nomes de constantes genéricos como
C
pode ser confuso e não indica o que a constante representa.
1 2 3 4 |
const C = 3.1415; |
Mas talvez use algo como CalcImps, ImpFedederais ou semelhante. Se esse é seu caso, procure melhorar esses nomes e torná-los mais legíveis.
Depois: Um nome descritivo como C_AliquotaFederal
ou C_AliquotaEstadual
(se fizer sentido) deixa claro que as constantes representam os valores de impostos federais e estaduais, respectivamente.
1 2 3 4 5 |
const C_AliquotaFederal = 7, C_AliquotaEstadual = 10; |
Percebe como fica mais claro?
Parâmetros de Função
Crucial essa parte. Primeiro, evite muitos parâmetros, mas vamos falar disso mais adiante em outro momento. Se precisar de parâmetros dê nomes significativos pra eles também. Criar parâmetros como abaixo, não é uma boa prática.
- Antes: Nomes de parâmetros genéricos como
x
ey
não indicam claramente o que os parâmetros representam.
O que é x e o que é y? Isso vai forçar o desenvolvedor a olhar o código da função pra decifrar o que são.
Parâmetros de Funções
A quantidade ideal de parâmetros para uma função é zero (nulo). Depois vem (mônade), seguido de (díade). Sempre que possível devem-se evitar três parâmetros (tríade). Para mais de três parâmetros deve-se ter um motivo muito especial (políade) – mesmo assim não devem ser usados.
Fonte: Código-Limpo de Robert C. Martin.
Como pôde perceber na citação do livro Código-Limpo, deve-se evitar parâmetros, mas já que precisamos, então vamos dar nomes melhores.
1 2 3 |
function (A, B: Double): Double; |
Imagine que a função acima é o cálculo de comissão de vendedores. Não dá pra saber qual é o valor da venda e qual o percentual de comissão. Ah, tá. Você não faz assim, é justo. Talvez faça assim:
1 2 3 4 5 6 |
function (VlrVnd, PercentComiss: Double): Double; begin // end; |
Dá pra melhlorar. Que tal fazermos assim:
1 2 3 4 5 6 |
function (AValorVenda, APercentualComissao: Double): Double; begin // end; |
Muito melhor não. Agora sabemos que o primeiro parâmetro é o valor da venda e o segundo o percentual de comissão. Pergunta: E esse “A” na frente, de onde vem?
A = Argument
É uma convenção do Delphi, não é obrigatório, porém totalmente válido. Você deve usar, muito provavelmente, o “v” ou ou o tipo de parâmetro na frentre: “s” para String, “i” para Inteiro, etc. Não use, use o A.
E talvez esteja pensando: Puxa, mas isso é simples demais, não acho que atrapalha tanto assim. Pois é, é o que a maioria dos devs acredita, entretanto perder alguns minutos na hora de entender um código-fonte antes de iniciar uma nova implementação, ao final do dia/mês, dá uma grande diferença. Portanto, atente-se aos detalhes.
Conclusão
Usar nomes significativos no código é um dos pilares fundamentais do código-limpo e um passo essencial para criar software de alta qualidade. Nomes bem escolhidos melhoram significativamente a legibilidade, facilitam a manutenção e a navegação pelo código, e reduzem a necessidade de comentários adicionais. Cada desenvolvedor que trabalha em um projeto se beneficia de nomes claros e descritivos, pois eles comunicam a intenção do código de forma direta e eficaz.
Investir tempo para pensar cuidadosamente nos nomes de variáveis, funções, métodos, classes e units resulta em um código mais coeso e autoexplicativo. Isso não só torna o desenvolvimento mais eficiente, mas também melhora a colaboração entre os membros da equipe, que podem facilmente entender e modificar o código sem introduzir novos erros.
Nomes significativos também ajudam a manter a consistência em um projeto, o que é crucial para a coesão do código. Essa prática deve ser adotada desde o início do desenvolvimento e mantida ao longo de todo o ciclo de vida do software, contribuindo para a criação de sistemas mais robustos e sustentáveis.
Em suma, nomes significativos são a base sobre a qual outros princípios de código-limpo podem ser construídos. No próximo artigo, exploraremos o segundo pilar do código-limpo: Funções Pequenas e Focadas, e como elas podem contribuir ainda mais para a qualidade do seu código.
Comunidade no Telegram
🚀Comente no campo abaixo 👇👇👇 o que achou e qual sua dúvida.
Te vejo na próxima
Adriano Santos
Demais Artigos:
Parte 1: Nomes Significativos
Parte 2: Funções Pequenas
Parte 3: Comentários Eficientes
Parrte 4: Formatação Consistente
Parte 5: Tratamento de Erros
Parte 6: Estrutura de Classes
Parte 7: Testes Automatizados
Parte 8: Refatoração Contínua
Parte 9: Código Simples e Direto
Parte 10: SOLID