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!! 👏👏👏