Huele porque es probable que haya muchos casos en los que podría editarse o mejorarse.
La mayoría de estos olores son solo indicios de algo que podría estar mal. No se requieren fijos per se... (Sin embargo, deberías investigarlo).
Continuemos...
No agregue IF para verificar el entorno de producción.
TL; DR: evite agregar condicionales relacionados con la producción
A veces, necesitamos crear diferentes comportamientos en el desarrollo y la producción.
Por ejemplo, la fortaleza de las contraseñas.
En este caso, necesitamos configurar el entorno con la estrategia de fuerza y probar la estrategia y no el entorno en sí.
def send_welcome_email(email_address, environment): if ENVIRONMENT_NAME == "production": print(f"Sending welcome email to {email_address} from Bob Builder <[email protected]>") else: print("Emails are sent only on production") send_welcome_email("[email protected]", "development") # Emails are sent only on production send_welcome_email("[email protected]", "production") # Sending welcome email to [email protected] from Bob Builder <[email protected]>
class ProductionEnvironment: FROM_EMAIL = "Bob Builder <[email protected]>" class DevelopmentEnvironment: FROM_EMAIL = "Bob Builder Development <[email protected]>" # 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("[email protected]", DevelopmentEnvironment()) # Sending welcome email to [email protected] from Bob Builder Development <[email protected]> send_welcome_email("[email protected]", ProductionEnvironment()) # Sending welcome email to [email protected] from Bob Builder <[email protected]>
Este es un olor de diseño.
Necesitamos crear configuraciones de desarrollo/producción vacías y delegarlas con objetos polimórficos personalizables.
Evite agregar condicionales no comprobables.
Crear configuraciones delegando reglas de negocio.
Utilice abstracciones, protocolos e interfaces, evite jerarquías estrictas.
Code Smell 56 - Preprocesadores
Foto de Birmingham Museums Trust en Unsplash
Este tuit fue inspirado por @Jan Giacomelli
La complejidad es un signo de inmadurez técnica. La simplicidad de uso es el verdadero signo de un producto bien diseñado, ya sea un cajero automático o un misil Patriot.
daniel t ling
Grandes citas de ingeniería de software
La reutilización de variables hace que los alcances y los límites sean más difíciles de seguir
TL; DR: no lea y escriba la misma variable para diferentes propósitos
Al programar un script, es común reutilizar variables.
Esto genera confusión y dificulta la depuración.
Debemos reducir el alcance tanto como sea posible.
// 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
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 ); }
Linters puede usar el árbol de análisis para encontrar definiciones y usos de variables.
Evite reutilizar nombres de variables. Use nombres más específicos y diferentes.
Code Smell 03 - Las funciones son demasiado largas
Refactorización 002 - Método de extracción
Simplicidad antes que generalidad, uso antes que reutilización.
kevlin henney
Grandes citas de ingeniería de software
Afirmar que dos números flotantes son iguales es un problema muy difícil
TL;DR: No compares flotadores
Comparar números flotantes es un viejo problema de informática.
La solución habitual es utilizar comparaciones de umbral.
Recomendamos evitar los flotantes y tratar de usar números de precisión infinitos.
Assert.assertEquals(0.0012f, 0.0012f); // Deprecated Assert.assertTrue(0.0012f == 0.0012f); // Not JUnit - Smell
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
Podemos agregar una verificación con assertEquals() en nuestros marcos de prueba para evitar la verificación de flotadores.
Siempre debemos evitar comparar flotadores.
Code Smell 71 - Flotadores mágicos disfrazados de decimales
Foto de Mika Baumeister en Unsplash
Dios hizo los números naturales; todo lo demás es obra del hombre.
Leopoldo Kronecker
Grandes citas de ingeniería de software
¿Qué pasa si combinas 4 olores de código?
TL;DR: Evitar Getters, Evitar Setters, Evitar Metaprogramación. Piensa en el Comportamiento.
Setters y getters son una mala práctica de la industria.
Muchos IDE favorecen este olor a código.
Algunos lenguajes brindan soporte explícito para construir modelos anémicos y DTO.
class Person { public string name { get; set; } }
class Person { private string name public Person(string personName) { name = personName; //imutable //no getters, no setters } //... more protocol, probably accessing private variable name }
Esta es una característica del lenguaje.
Debemos evitar lenguajes inmaduros o prohibir sus peores prácticas.
Necesitamos pensar cuidadosamente antes de exponer nuestras propiedades.
El primer paso es dejar de pensar en propiedades y centrarse únicamente en el comportamiento.
Code Smell 70 - Generadores de modelos anémicos
Code Smell 01 - Modelos anémicos
No hay nada más difícil que trabajar con un plazo ajustado y aun así tomarse el tiempo para limpiar sobre la marcha.
Kent Beck
Grandes citas de ingeniería de software
Predeterminado significa 'todo lo que aún no sabemos'. No podemos prever el futuro.
TL; DR: no agregue una cláusula predeterminada a sus casos. Cámbialo por una excepción. Sea explícito.
Cuando usamos casos, generalmente agregamos un caso predeterminado para que no falle.
Fallar siempre es mejor que tomar decisiones sin pruebas.
Dado que la caja y los interruptores también son un olor, podemos evitarlos.
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; }
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; }
Podemos decirle a nuestros linters que nos adviertan sobre los usos predeterminados a menos que haya una excepción.
Escribir código robusto no significa que debamos tomar decisiones sin evidencia.
Code Smell 36 - Declaraciones Switch/case/elseif/else/if
Foto de Joshua Woroniecki en Unsplash
El costo de agregar una función no es solo el tiempo que toma codificarla. El costo también incluye la adición de un obstáculo para la futura expansión. El truco consiste en elegir las características que no luchan entre sí.
Juan Carmack
Grandes citas de ingeniería de software
Y eso es todo por ahora…
¡El próximo artículo explicará 5 olores de código más!