Cheiros de código são um clássico. 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. Eles não são necessariamente consertados per se ... (Você deve investigar isso.) Código anterior cheira Parte I parte II Parte III Parte IV Parte V Parte VI Parte VII Parte VIII Parte IX Parte X Parte XI Parte XII Parte XIII Parte XIV Parte XV Parte XVI Parte XVII Parte XVIII Parte XIX Parte XX Parte XXI Vamos continuar... Cheiro de Código 106 - Código Dependente de Produção Não adicione IFs verificando o ambiente de produção. TL;DR: Evite adicionar condicionais relacionados à produção problemas Falha na violação do princípio rápido Falta de testabilidade Soluções Se for absolutamente necessário, modele ambientes e teste eles. TODOS Contexto Às vezes, precisamos criar comportamentos diferentes no desenvolvimento e na produção. Por exemplo, a força das senhas. Nesse caso, precisamos configurar o ambiente com a estratégia de força e testar a estratégia e não o ambiente em si. Código de amostra Errado def send_welcome_email(email_address, environment): if ENVIRONMENT_NAME == "production": print(f"Sending welcome email to {email_address} from Bob Builder <bob@builder.com>") else: print("Emails are sent only on production") send_welcome_email("john@doe.com", "development") # Emails are sent only on production send_welcome_email("john@doe.com", "production") # Sending welcome email to john@doe.com from Bob Builder <bob@builder.com> Certo class ProductionEnvironment: FROM_EMAIL = "Bob Builder <bob@builder.com>" class DevelopmentEnvironment: FROM_EMAIL = "Bob Builder Development <bob@builder.com>" # We can unit test environments # and even implement different sending mechanisms def send_welcome_email(email_address, environment): print(f"Sending welcome email to {email_address} from {environment.FROM_EMAIL}") # We can delegate into a fake sender (and possible logger) # and unit test it send_welcome_email("john@doe.com", DevelopmentEnvironment()) # Sending welcome email to john@doe.com from Bob Builder Development <bob@builder.com> send_welcome_email("john@doe.com", ProductionEnvironment()) # Sending welcome email to john@doe.com from Bob Builder <bob@builder.com> Detecção manual [x] Este é um cheiro de design. Precisamos criar configurações vazias de desenvolvimento/produção e delegá-las com objetos polimórficos personalizáveis. Tag Acoplamento Conclusão Evite adicionar condicionais não testáveis. Crie configurações delegando regras de negócio. Use abstrações, protocolo e interfaces, evite hierarquias rígidas. Relações Code Smell 56 - Pré-processadores Mais informações Como evitar ifs irritantes Créditos Foto de no Birmingham Museums Trust Unsplash Este tweet foi inspirado por @ Jan Giacomelli Twitter A complexidade é um sinal de imaturidade técnica. Simplicidade de uso é o sinal real de um produto bem projetado, seja um ATM ou um míssil Patriot. Daniel T. Ling Grandes Citações de Engenharia de Software Code Smell 107 - Reutilização de Variáveis A reutilização de variáveis torna os escopos e limites mais difíceis de seguir TL;DR: Não leia e escreva a mesma variável para propósitos diferentes problemas Legibilidade problemas ocultos Soluções Não reutilize variáveis para isolar escopos Extrair método Contexto Ao programar um script é comum reutilizar variáveis. Isso causa confusão e dificulta a depuração. Devemos restringir o escopo o máximo possível. Código de amostra Errado // print line total double total = item.getPrice() * item.getQuantity(); System.out.println("Line total: " + total ); // print amount total total = order.getTotal() - order.getDiscount(); System.out.println( "Amount due: " + total ); // variable is reused Certo function printLineTotal() { double total = item.getPrice() * item.getQuantity(); System.out.println("Line total: " + total ); } function printAmountTotal() { double total = order.getTotal() - order.getDiscount(); System.out.println( "Amount due: " + total ); } Detecção Automático [ ] Os Linters podem usar a árvore de análise para encontrar definições e usos de variáveis. Tag Legibilidade Conclusão Evite reutilizar nomes de variáveis. Use nomes mais específicos e diferentes. Relações Cheiro de código 03 - as funções são muito longas Mais informações Refatoração 002 - Método Extrair Créditos Foto de no Sigmund Unsplash Simplicidade antes da generalidade, uso antes da reutilização. Kevlin Henney Grandes Citações de Engenharia de Software Code Smell 108 - Float Assertions Afirmar que dois números float são iguais é um problema muito difícil TL;DR: Não compare floats problemas resultados de teste errados Testes frágeis Falha na violação do princípio rápido Soluções Evite flutuações, a menos que você tenha problemas de desempenho REAIS Use números de precisão arbitrária Se você precisar comparar os flutuadores, compare com a tolerância. Contexto Comparar números float é um antigo problema da ciência da computação. A solução usual é usar comparações de limite. Recomendamos evitar flutuações e tentar usar números de precisão infinita. Código de amostra Errado Assert.assertEquals(0.0012f, 0.0012f); // Deprecated Assert.assertTrue(0.0012f == 0.0012f); // Not JUnit - Smell Certo Assert.assertEquals(0.0012f, 0.0014f, 0.0002); // true Assert.assertEquals(0.0012f, 0.0014f, 0.0001); // false // last parameter is the delta threshold Assert.assertEquals(12 / 10000, 12 / 10000); // true Assert.assertEquals(12 / 10000, 14 / 10000); // false Detecção Automático [ ] Podemos adicionar uma verificação com em nossas estruturas de teste para evitar a verificação de flutuações. assertEquals() Tag Testar odores Conclusão Devemos sempre evitar comparar floats. Relações Code Smell 71 - Flutuadores Mágicos Disfarçados de Decimais Mais informações Falha rápido Créditos Foto de no Mika Baumeister Unsplash Deus fez os números naturais; tudo o mais é obra do homem. Leopold Kronecker Grandes Citações de Engenharia de Software Cheiro de Código 109 - Propriedades Automáticas O que acontece se você combinar 4 code smells? TL;DR: Evite getters, evite setters, evite metaprogramação. Pense no Comportamento. problemas Violação de ocultação de informações Mutabilidade Violação do princípio Fail Fast Código duplicado ao definir propriedades Soluções Remover setters e getters automáticos Contexto Setters e getters são uma má prática da indústria. Muitos IDEs favorecem esse cheiro de código. Algumas linguagens fornecem suporte explícito para construir modelos anêmicos e DTOs. Código de amostra Errado class Person { public string name { get; set; } } Certo class Person { private string name public Person(string personName) { name = personName; //imutable //no getters, no setters } //... more protocol, probably accessing private variable name } Detecção Automático [ ] Este é um recurso de linguagem. Devemos evitar línguas imaturas ou proibir suas piores práticas. Tag Encapsulamento Conclusão Precisamos pensar bem antes de expor nossas propriedades. O primeiro passo é parar de pensar em propriedades e focar apenas no comportamento. Relações Code Smell 28 - Setters Code Smell 68 - Getters Code Smell 70 - Geradores de modelos anêmicos Code Smell 40 - DTOs Cheiro de Código 01 - Modelos Anêmicos Mais informações escolas W3 Preguiça I - Metaprogramação Preguiça II - Assistentes de Código Refatoração 001 - Remover Setters O poder maligno dos mutantes Falhar rápido Créditos Foto de no Kony Unsplash Nada é mais difícil do que trabalhar com um prazo apertado e ainda reservar um tempo para limpar enquanto trabalha. Kent Beck Grandes Citações de Engenharia de Software Code Smell 110 - Switches com padrões Padrão significa 'tudo o que ainda não sabemos'. Não podemos prever o futuro. TL;DR: Não adicione uma cláusula padrão aos seus casos. Altere-o para uma exceção. Seja explícito. problemas Acoplamento Violação do princípio Fail Fast Violação do princípio aberto fechado Soluções Substitua if e cases por polimorfismo Altere o código padrão para uma exceção Contexto Ao usar casos, geralmente adicionamos um caso padrão para que não falhe. Falhar é sempre melhor do que tomar decisões sem provas. Como o também são um cheiro, podemos evitá-los. gabinete e os interruptores Código de amostra Errado switch (value) { case value1: // if value1 matches the following will be executed.. doSomething(); break; case value2: // if value2 matches the following will be executed.. doSomethingElse(); break; default: // if value does not presently match the above values // or future values // the following will be executed doSomethingSpecial(); break; } Certo switch (value) { case value1: // if value1 matches the following will be executed.. doSomething(); break; case value2: // if value2 matches the following will be executed.. doSomethingElse(); break; case value3: case value4: // We currently know these options exist doSomethingSpecial(); break; default: // if value does not match the above values we need to take a decision throw new Exception('Unexpected case ' + value + ' we need to consider it'); break; } Detecção Semiautomático [x] Podemos dizer aos nossos linters para nos avisar sobre usos padrão, a menos que haja uma exceção. Tag Falhar rápido Conclusão Escrever código robusto não significa que precisamos tomar decisões sem evidências. Relações Cheiro de código 36 - instruções switch/case/elseif/else/if Mais informações Falhar rápido Créditos Foto de no Joshua Woroniecki Unsplash O custo de adicionar um recurso não é apenas o tempo necessário para codificá-lo. O custo também inclui a adição de um obstáculo à expansão futura. O truque é escolher os recursos que não lutam entre si. John Carmack Grandes Citações de Engenharia de Software E isso é tudo por agora… O próximo artigo explicará mais 5 code smells!