Article image
Idarlene Pinto
Idarlene Pinto25/10/2023 17:05
Compartilhe

Clean Code: A arte de n√£o enlouquecer programando ūüėé

  • #Arquitetura de Sistemas

Bem-vindo(a) ao impressionante mundo do Clean Code ūü§©, onde a programa√ß√£o torna-se uma jornada clara e organizada. Imagine-se como o protagonista de uma hist√≥ria, onde cada linha de c√≥digo √© uma p√°gina emocionante do seu di√°rio.


Em certas ocasi√Ķes, a programa√ß√£o √© capaz de se transformar em um quebra-cabe√ßa, mas √© neste cen√°rio que o Clean Code entra em a√ß√£o. Ele age como um guia confi√°vel, orientando e transformando o caminho da programa√ß√£o e tornando a jornada mais clara e objetiva.


Neste artigo, vamos explorar o Clean Code, onde os princípios do código limpo são como guias que auxiliam a navegar pelo código com confiança. Esses princípios tornam sua jornada mais eficiente e a manutenção do código mais fácil, transformando-o em um recurso valioso.


À medida que exploramos o Clean Code, você perceberá que a programação pode ser mais fascinante e mágica, onde a clareza e a organização são seus guias. Juntos, vamos desvendar os segredos desse universo e tornar a programação uma experiência ainda mais surpreendente e gratificante.

Mas, o que é esse tal de Clean Code?

image

Figura 1 - Código Limpo

Atualmente, a maioria das empresas enfrenta desafios significativos relacionados à qualidade do código. Isso resulta em problemas como a acumulação de defeitos, a insatisfação dos clientes e a dificuldade de manter os projetos dentro do orçamento.


Nesse cen√°rio, o conceito de Clean Code, surge como uma solu√ß√£o fundamental para aprimorar a programa√ß√£o, com foco na clareza, legibilidade e facilidade de manuten√ß√£o. Dessa forma, o desenvolvimento de aplica√ß√Ķes com c√≥digos de qualidade √© garantido e eles podem ser reutilizados com facilidade.


Em suas palavras, Robert C. Martin, autor do renomado livro "Clean Code: A Handbook of Agile Software Craftsmanship," fez uma analogia brilhante ao afirmar:


"Escrever um código limpo é como pintar um quadro. A maioria de nós sabe quando a figura foi bem ou mal pintada. Mas distinguir uma boa arte de uma ruim não significa que você saiba pintar. Assim como saber distinguir um código limpo de um ruim não quer dizer que saibamos escrever um código limpo."


Essa observa√ß√£o destaca o qu√£o √© importante compreender a diferen√ßa entre reconhecer o c√≥digo limpo e ser capaz de escrev√™-lo. Como um artista, o programador deve se empenhar para que seja poss√≠vel. √Č por essa raz√£o que eu penso que a leitura da obra de Robert C. Martin deveria ser obrigat√≥ria para todos os programadores de todos os n√≠veis.


Lembrem-se, jovens padawans da programação, que um código que é fácil de entender e de modificar é como um artefato mágico que todos adoram. Com frequência, no desenvolvimento, ninguém deseja herdar um projeto com código de baixa qualidade ou confuso.


Às vezes, os desenvolvedores evitam escrever código limpo porque estão sendo perseguidos pelo implacável monstro do prazo. Eles correm, mas, na realidade, acabam indo mais devagar e deixam um rastro de bugs. 

image

Figura 2 - Tempo vs Programação


Por isso, usar um código limpo e de fácil leitura é mais do que uma prática, é um investimento a longo prazo. Segundo Robert C. Martin:


‚ÄúQualquer um consegue escrever c√≥digo que o computador entende. Bons programadores escrevem c√≥digo que humanos entendem.‚ÄĚ

Boas pr√°ticas do nosso amado Clean Code


Welcome, jovens programadores, a uma aventura no maravilhoso mundo do Clean Code. Onde os c√≥digos s√£o organizados, os nomes das vari√°veis fazem sentido e os coment√°rios n√£o s√£o mais misteriosos do que as previs√Ķes do hor√≥scopo.


Preparem-se para descobrir como escrever c√≥digo t√£o limpo que at√© aspiradores de p√≥ ficariam com inveja. Ent√£o, relaxe e divirta-se enquanto exploramos as boas pr√°ticas que tornaram seu c√≥digo t√£o elegante que at√© mesmo o c√≥digo fonte alheio ficar√° com ci√ļmes.


E lembrem-se, não há maneira melhor de aprender do que com os erros. Então, preparem-se para dar boas risadas com exemplos do que não fazer. Estamos prestes a embarcar em uma jornada de aprendizado, risos e, claro, muita programação limpa.


Os princípios do Clean Code

Os princípios do Clean Code são diretrizes de boas práticas que visam tornar o código fonte mais legível, compreensível e fácil de manter. Alguns dos princípios incluem:


  • Princ√≠pio da Responsabilidade √önica: Cada classe ou fun√ß√£o deve ter apenas uma responsabilidade bem definida.


Imagine que cada classe ou função é como um convidado em uma festa. Cada um tem um papel específico, não queremos que um convidado tente ser o DJ, o garçom e o dançarino ao mesmo tempo, certo?


Um exemplo real desta situação pode ser observado na Figura 3, onde a classe GerenciadorDePedidos possuem duas responsabilidades distintas: gerenciar pedidos e gerar relatório. Isso viola o princípio da Responsabilidade Única, uma vez que a classe deveria ter apenas uma razão para mudar.


image

Figura 3 ‚Äď Exemplo a ser evitado


Para seguir o princ√≠pio, a solu√ß√£o reside na divis√£o dessas responsabilidades em classes separadas, Figura 4. Nesse novo cen√°rio, foram criadas duas classes distintas, cada uma com uma √ļnica fun√ß√£o. Isso resulta em um c√≥digo mais organizado e simplifica a manuten√ß√£o do sistema.


image

Figura 4 ‚Äď Exemplo a ser seguido

 

  • Princ√≠pio do Aberto/Fechado: O c√≥digo deve permanecer aberto para expans√£o, mas fechado para modifica√ß√£o.


Pense nele como uma deliciosa pizza: você pode adicionar novos sabores de cobertura, mas não deve mexer na massa. Expansão, sim! Bagunça, não!


Imagine uma classe chamada Calculadora respons√°vel por diversas opera√ß√Ķes matem√°ticas (Figura 5). Caso queira adicionar uma nova opera√ß√£o, a primeira tenta√ß√£o √© mexer na classe Calculadora, certo? No entanto, isso vai contra o princ√≠pio.


image

Figura 5 - Exemplo a ser evitado


Para seguir essa diretriz, podemos utilizar o polimorfismo e herança (Figura 6). Criamos subclasses (Adicao, Subtracao, Multiplicacao) que herdam da classe base Calculadora. Cada operação tem sua própria implementação do método calcular.


Voil√†! Adicionar novas opera√ß√Ķes torna-se simples, sem perturbar as classes existentes.


image

Figura 6 - Exemplo a ser seguido


Essa abordagem garante que a expans√£o do c√≥digo ocorra sem perturba√ß√Ķes. √Č como adicionar novos sabores √† sua pizza favorita, mantendo a base intacta.


  • Princ√≠pio de Substitui√ß√£o de Liskov: Classes derivadas devem ser substitu√≠veis por suas classes base, sem afetar a integridade do programa.


Pense nas classes derivadas como dublês de cinema, elas devem entrar em cena sem causar confusão e arruinar o filme.


Considere uma hierarquia de classes de formas geométricas (Figura 7), com Retangulo e Quadrado. A ideia é que você possa substituir uma classe derivada (Quadrado) pela classe base (Retangulo) sem bagunçar tudo. Mas, oh não! A redefinição do construtor torna essa substituição problemática.


image

Figura 7 - Exemplo a ser evitado


Para seguir o princípio, a abordagem é projetar suas classes para que, uma classe derivada (Quadrado) possa ser substituída pela classe base (Retangulo) sem afetar o comportamento do programa, Figura 8. Logo, você pode evitar a herança entre Quadrado e Retangulo e criar uma hierarquia de classes.


image

Figura 8 - Exemplo a ser seguido


Neste exemplo, a hierarquia de classes segue o princípio, pois você pode substituir qualquer objeto Retangulo por um objeto Quadrado sem afetar o comportamento do programa. Cada classe respeita a mesma interface, representada pelo método area, o que permite uma substituição segura.

 

  • Princ√≠pio de Segrega√ß√£o de Interfaces: As interfaces de uma classe devem ser espec√≠ficas para o cliente que as utiliza.


Imagine essas interfaces como um menu de restaurante. Você só precisa escolher o que gosta, não quer um prato de lagosta se veio para um churrasco, não é?


 Suponha que você tenha uma interface chamada Trabalhador que contém métodos trabalhar e comer, Figura 9.


image

Figura 9 - Exemplo A a ser evitado


Agora, imagine que você tem duas classes, Programador e Garcom, que implementam essa interface, Figura 10.


image

Figura 10 - Exemplo B a ser evitado

 

Nesse exemplo, ambas as classes precisam implementar os métodos comer, mesmo que isso não faça sentido para um programador ou garcom. Isso viola o princípio de Segregação de Interfaces, uma vez que as interfaces não devem forçar as classes a implementar métodos que não são relevantes para elas.


Para seguir o princípio de Segregação de Interfaces, você deve dividir a interface em interfaces menores e mais específicas. Por exemplo, você pode ter uma interface Trabalhador e outra interface Comedor, cada uma com métodos apropriados Figura 11.


image

Figura 11 - Exemplo A a ser seguido


Em seguida, você pode implementar essas interfaces nas classes relevantes.


image

Figura 12 - Exemplo B a ser seguido


Neste exemplo (Figura 12), o princípio de Segregação de Interfaces é seguido, uma vez que cada classe implementa apenas as interfaces relevantes para ela. Isso torna o código mais coeso e evita a necessidade de implementar métodos desnecessários.

 

  • Princ√≠pio da Invers√£o de Depend√™ncia: M√≥dulos de alto n√≠vel n√£o devem depender dos de baixo n√≠vel, e os detalhes devem depender de abstra√ß√Ķes.


Pense nos módulos como um castelo de cartas. Os andares superiores não devem depender dos inferiores, ou então a coisa toda desmorona. E os detalhes? Eles são como o glitter, sempre melhor quando dependem de algo maior e mais brilhante.


Suponha que você tenha uma classe Lampada que depende diretamente da classe Interruptor para ligar e desligar, Figura 13.


image

Figura 13 - Exemplo a ser evitado

 

Neste exemplo, a classe Lampada está diretamente acoplada à classe Interruptor, o que dificulta reutilizar a classe Lampada com diferentes dispositivos de controle de energia. Violando a lei de não dependência da classe inferior.


Para seguir o princípio da Inversão de Dependência, você pode introduzir uma interface abstrata, como DispositivoControle, e fazer com que tanto o Interruptor quanto Lampada dependam dessa interface, Figura 14.


image

Figura 14 - Exemplo a ser seguido

 

Agora, tanto o Interruptor quanto Lampada dependem da abstra√ß√£o DispositivoControle. Permitindo que voc√™ adicione novos dispositivos de controle ou l√Ęmpadas sem modificar as classes existentes.


Além disso, você pode facilmente substituir um dispositivo de controle por outro, desde que eles implementem a mesma interface.

 

  • Princ√≠pio da Composi√ß√£o sobre Heran√ßa: Prefira a composi√ß√£o de objetos ao inv√©s de heran√ßa ao projetar classes.


Na programa√ß√£o, isso √© como escolher entre herdar o guarda-roupa do seu av√ī ou montar o seu pr√≥prio. A composi√ß√£o permite que voc√™ customize seu c√≥digo sem ficar preso nas tend√™ncias do passado. Seu c√≥digo merece ser flex√≠vel e estar na moda.


Suponha que você esteja criando uma classe para representar animais, e você decide usar herança para criar subclasses de animais específicas, como Cachorro e Gato, Figura 15.


image

Figura 15 - Exemplo a ser evitado

 

Neste exemplo, utiliza-se a herança para criar subclasses de animais específicas. Contudo, isso pode levar a problemas quando você precisa adicionar comportamentos diferentes, como voar para aves ou nadar para peixes, e você pode acabar com uma hierarquia de herança complexa e difícil de manter.


Em vez de usar heran√ßa, voc√™ pode usar a composi√ß√£o para criar classes de animais, onde voc√™ comp√Ķe objetos com comportamentos espec√≠ficos em vez de herdar esses comportamentos, Figura 16.


image

Figura 16 - Exemplo a ser seguido

 

Neste exemplo, você usa composição para criar objetos de comportamento e os associa a objetos Animal. Isso permite que você adicione facilmente novos comportamentos sem modificar as classes existentes e segue o princípio da Composição sobre Herança.


Essa abordagem torna o c√≥digo mais flex√≠vel e evita hierarquias de heran√ßa complicadas e dif√≠ceis de gerenciar. √Č uma pr√°tica recomendada quando se lida com casos em que a heran√ßa pode ser inadequada.


  • Princ√≠pio da Minimiza√ß√£o do Acoplamento: Reduza as depend√™ncias entre m√≥dulos ou classes, tornando-as independentes umas das outras.


Isso é como construir um castelo de cartas. Quanto menos cartas apoiando umas nas outras, menos provável é que tudo desmorone quando você precisar fazer uma mudança. Afinal, ninguém quer que seu código seja tão frágil quanto um castelo de cartas em um furacão.


Suponha que você tenha uma classe Pedido que possui uma função para calcular o valor total do pedido e uma função para enviar um e-mail de confirmação do pedido, Figura 17.


image

Figura 17 - Exemplo a ser evitado


A classe Pedido está fortemente acoplada a enviar e-mails. Isso significa que, se você desejar alterar a maneira como os e-mails são enviados, precisará modificar a classe Pedido, violando o princípio da Minimização do Acoplamento.


Para minimizar o acoplamento, você pode separar as responsabilidades de calcular o valor total do pedido e enviar um e-mail de confirmação em classes separadas.


image

Figura 18 - Exemplo a ser seguido


Agora, a classe Pedido lida apenas com a lógica de negócios relacionada ao pedido, e a classe EnviadorEmail lida apenas com o envio de e-mails. Isso reduz o acoplamento entre as classes e facilita a manutenção e a modificação de cada parte do sistema independentemente.


Seguir o princípio da Minimização do Acoplamento ajuda a criar um código mais flexível e facilita a manutenção e expansão do sistema. Além disso, torna o código mais reutilizável em diferentes contextos.


  • Princ√≠pio da M√°xima Coes√£o: Mantenha as funcionalidades relacionadas agrupadas em um mesmo m√≥dulo, classe ou fun√ß√£o.


Pense nisso como montar um sanduíche. Você não coloca ketchup na base e alface no topo, certo? Mantenha as coisas organizadas, assim como um sanduíche bem montado!


Suponha que você tenha uma classe chamada ManipuladorArquivo que tem várias responsabilidades, como ler, escrever, renomear e excluir arquivos, Figura 19.


image

Figura 19 - Exemplo a ser evitado


Neste exemplo, a classe ManipuladorArquivo tem muitas responsabilidades diferentes e n√£o est√° altamente coesa. Isso dificulta a manuten√ß√£o e compreens√£o da classe, e viola o princ√≠pio da M√°xima Coes√£o, que sugere que uma classe deve ter uma √ļnica responsabilidade bem definida.


Para seguir o princ√≠pio da M√°xima Coes√£o, voc√™ deve dividir as responsabilidades em classes separadas, cada uma com uma √ļnica responsabilidade bem definida.¬†


image

Figura 20 - Exemplo a ser seguido


Agora, cada classe tem uma √ļnica responsabilidade relacionada √† manipula√ß√£o de arquivos. Isso melhora a coes√£o, facilita a manuten√ß√£o e torna o c√≥digo mais compreens√≠vel.


Seguir o princípio da Máxima Coesão ajuda a criar classes mais focadas e fáceis de manter, contribuindo para um código mais organizado e eficiente.


  • Princ√≠pio da Legibilidade: Escreva o c√≥digo de forma clara, com nomes descritivos para as vari√°veis e fun√ß√Ķes, evite coment√°rios desnecess√°rios e formate o c√≥digo de maneira consistente.


Imagine isto como dar dire√ß√Ķes para um GPS. Use nomes de estrada claros, evite becos sem sa√≠da e mantenha o caminho sem obst√°culos.


¬† Suponha que voc√™ tenha uma fun√ß√£o que realiza uma s√©rie de c√°lculos complexos e n√£o utiliza nomes descritivos para vari√°veis e fun√ß√Ķes, Figura 21.


image

Figura 21 - Exemplo a ser evitado

Neste exemplo, as variáveis a, b e c têm nomes pouco descritivos, tornando o código difícil de entender. Além disso, os cálculos são complexos e não há comentários explicativos.


Para melhorar a legibilidade, voc√™ deve usar nomes descritivos para vari√°veis e fun√ß√Ķes e adicionar coment√°rios explicativos quando necess√°rio, Figura 22.


Neste exemplo, as variáveis têm nomes descritivos, e há comentários explicativos que ajudam a entender o propósito de cada etapa do cálculo. Isso torna o código muito mais legível e compreensível.


image

Figura 22 - Exemplo a ser seguido


Seguir o princípio da Legibilidade é fundamental para facilitar a manutenção, colaboração e depuração de código. Códigos mais legíveis são mais fáceis de entender e menos propensos a erros.


  • Princ√≠pio do C√≥digo DRY: Evite repetir o mesmo c√≥digo em v√°rios lugares. Coloque o c√≥digo repetitivo em fun√ß√Ķes ou classes reutiliz√°veis.


Isto √© como n√£o contar a mesma piada v√°rias vezes. Ela perde a gra√ßa, e o p√ļblico fica entediado. Coloque o c√≥digo repetitivo em um ‚Äúlivro de piadas‚ÄĚ reutiliz√°veis, como fun√ß√Ķes ou classes, e mantenha sua audi√™ncia (e seu c√≥digo) sempre sorrindo.¬†


Suponha que voc√™ esteja trabalhando em um programa que calcula a √°rea e o per√≠metro de diferentes formas geom√©tricas, como quadrados, ret√Ęngulos e c√≠rculos. No c√≥digo a seguir (Figura 23), voc√™ repete o c√°lculo da √°rea para cada tipo de forma, mesmo que a f√≥rmula para calcular a √°rea seja a mesma.


image

Figura 23 - Exemplo a ser evitado

 

Neste exemplo, a lógica para calcular a área está repetida em cada classe, o que viola o princípio do DRY.


Para seguir o princípio do DRY, você pode criar uma classe base comum que contenha a lógica para calcular a área e, em seguida, herdar essa classe base nas classes específicas de cada forma geométrica.


image

Figura 24 - Exemplo a ser seguido

 

Agora, a lógica para calcular a área está centralizada na classe base FormaGeometrica, e as classes específicas herdam essa lógica. Isso elimina a repetição de código e segue o princípio do DRY.


Seguir o princípio do DRY ajuda a reduzir a duplicação de código, torna o código mais fácil de manter e evita inconsistências nas diferentes partes do programa.


E assim, nossa jornada no maravilhoso mundo do Clean Code continua. Espero que voc√™s tenham se divertido e aprendido muito, como eu ūüėú. Manter seu c√≥digo limpo n√£o √© apenas uma pr√°tica inteligente, mas tamb√©m uma aventura empolgante em busca da excel√™ncia na programa√ß√£o.


C√≥digo limpo √© uma forma de arte que todos os programadores deveriam buscar dominar, o Santo Graal da programa√ß√£o. Ent√£o programadores, que os c√≥digos estejam sempre limpos e suas aventuras sejam √©picas. Agora s√≥ √© para frente, n√£o tem mais volta! ūüĎ®‚ÄćūüíĽūüöÄūüí°



Referências:

Martin, Robert C. (2008). Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall.

Compartilhe
Coment√°rios (1)
Milena Miron
Milena Miron - 26/10/2023 09:08

Sensacional!! ūüĎŹūüĎŹūüĎŹ