Cheira porque provavelmente há muitos casos em que poderia ser editado ou melhorado.
A maioria desses cheiros são apenas indícios de algo que pode estar errado. Portanto, eles não precisam ser consertados per se... (Você deve dar uma olhada nisso, no entanto.)
Você pode encontrar todos os cheiros de código anteriores (Parte i - XXVIII) aqui.
Vamos continuar...
Você já viu um IEngine em estado selvagem?
TL;DR: Não prefixe ou sufixe suas classes
Algumas linguagens têm convenções culturais relacionadas a tipos de dados, classes abstratas ou interfaces. Esses nomes carregam nossos modelos com traduções cognitivas difíceis de seguir.
Devemos BEIJAR .
public interface IEngine { void Start(); } public class ACar { } public class ImplCar { } public class CarImpl { }
public interface Engine { void Start(); } public class Vehicle { } public class Car { }
Se tivermos um dicionário de sinônimos, podemos apontar nomes estranhos.
Em C#, é comum colocar "I" no nome de uma interface porque, sem ele, não dá para saber se é uma interface ou uma classe.
Este é um cheiro de linguagem.
Use nomes reais para seus modelos.
Foto de Tim Mossholder no Unsplash
Algumas pessoas, quando confrontadas com um problema, pensam “eu sei, vou usar expressões regulares”. Agora eles tem dois problemas.
Jamie Zawinski
Grandes Citações de Engenharia de Software
Acessar um banco de dados em objetos de domínio é um cheiro de código. Fazer isso em um construtor é um cheiro duplo.
TL;DR: Construtores devem construir (e provavelmente inicializar) objetos.
No código legado, o banco de dados não está separado corretamente dos objetos de negócios.
Construtores nunca devem ter efeitos colaterais.
De acordo com o princípio da responsabilidade única, eles só devem construir objetos válidos
public class Person { int childrenCount; public Person(int id) { childrenCount = database.sqlCall("SELECT COUNT(CHILDREN) FROM PERSON WHERE ID = " . id); } }
public class Person { int childrenCount; // Create a class constructor for the Main class public Person(int id, int childrenCount) { childrenCount = childrenCount; // We can assign the number in the constructor // Accidental Database is decoupled // We can test the object } }
Nossos linters podem encontrar padrões SQL em construtores e nos avisar.
A separação de preocupações é fundamental e o acoplamento é nosso principal inimigo ao projetar um software robusto.
<span>Foto de Callum Hill no Unsplash </span>
Minha crença ainda é que, se você acertar as estruturas de dados e suas invariantes, a maior parte do código se escreverá sozinho.
Peter Deustch
Grandes Citações de Engenharia de Software
Alguns objetos estão sempre juntos. Por que não os separamos?
TL;DR: Faz com que objetos primitivos coesos viajem juntos
Esse cheiro é amigo da obsessão primitiva.
Se dois ou mais objetos primitivos estiverem colados, com lógica de negócios repetida e regras entre eles, precisamos encontrar o conceito existente de bijeção .
public class DinnerTable { public DinnerTable(Person guest, DateTime from, DateTime to) { Guest = guest; From = from; To = to; } private Person Guest; private DateTime From; private DateTime To; }
public class TimeInterval { public TimeInterval(DateTime from, DateTime to) { // We should validate From < To From = from; To = to; } } public DinnerTable(Person guest, DateTime from, DateTime to) { Guest = guest; Interval = new TimeInterval(from, to); } // Even Better... public DinnerTable(Person guest, Interval reservationTime) { Guest = guest; Interval = reservationTime; }
A detecção baseada em padrões de coesão está disponível em alguns linters.
Agrupe o comportamento no lugar certo e oculte os dados primitivos.
Code Smell 122 - Obsessão Primitiva
Cheiro de Código 01 - Modelos Anêmicos
Cheiro de Código 27 - Arrays Associativos
Foto de Dynamic Wang no Unsplash
O coração do software é sua capacidade de resolver problemas relacionados ao domínio para seu usuário. Todos os outros recursos, por mais vitais que sejam, suportam esse propósito básico.
Eric Evans
Grandes Citações de Engenharia de Software
Ouvimos muito sobre NFTs. Agora, dominamos o conceito Fungível.
TL;DR: Respeite o MAPPER . Tornar fungível o que é fungível no mundo real e vice-versa.
De acordo com a Wikipédia :
Fungibilidade é a propriedade de um bem ou mercadoria cujas unidades individuais são essencialmente intercambiáveis e cada uma de cujas partes é indistinguível de outra parte.
Em software, podemos substituir objetos fungíveis por outros.
Ao mapear nossos objetos com os reais, às vezes nos esquecemos do modelo parcial e construímos sobre o design.
public class Person implements Serializable { private final String firstName; private final String lastName; public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } } shoppingQueueSystem.queue(new Person('John', 'Doe'));
public class Person { } shoppingQueueSystem.queue(new Person()); // The identity is irrelevant for queue simulation
Este é um cheiro semântico.
Precisamos entender o modelo para verificar se está certo ou não.
Tornar fungível o que é fungível e vice-versa.
Parece fácil, mas requer habilidades de design e evitar a complexidade acidental.
Foto de Andrey Metelev no Unsplash
As pessoas pensam que a ciência da computação é a arte dos gênios, mas a realidade é o oposto, apenas muitas pessoas fazendo coisas que constroem umas sobre as outras, como uma parede de minipedras.
Donald Knuth
Não use a avaliação booleana como um atalho de legibilidade.
TL;DR: Não use comparação booleana para funções de efeito colateral.
Programadores inteligentes gostam de escrever códigos obscuros e obscuros, mesmo quando não há evidências fortes para essa melhoria.
A otimização prematura sempre prejudica a legibilidade.
userIsValid() && logUserIn(); // this expression is short circuit // Does not value second statement // Unless the first one is true functionDefinedOrNot && functionDefinedOrNot(); // in some languages undefined works as a false // If functionDefinedOrNot is not defined does // not raise an error and neither runs
if (userIsValid()) { logUserIn(); } if(typeof functionDefinedOrNot == 'function') { functionDefinedOrNot(); } // Checking for a type is another code smell
Podemos verificar se as funções são impuras e mudar o curto-circuito para um IF.
Alguns linters atuais nos alertam sobre esse problema
Não tente parecer inteligente.
Não estamos mais na década de 50.
Seja um desenvolvedor de equipe.
Code Smell 140 - Avaliação de Curto Circuito
Code Smell 06 - Programador Muito Inteligente
Code Smell 149 - Encadeamento opcional
Foto de Michael Dziedzic no Unsplash
Um computador é uma máquina estúpida com a capacidade de fazer coisas incrivelmente inteligentes, enquanto os programadores de computador são pessoas inteligentes com a capacidade de fazer coisas incrivelmente estúpidas. Eles são, em suma, uma combinação perfeita.
Bill Bryson
Próximo artigo: 5 mais cheiros de código.