Los olores a código son un clásico.
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).
Olores de código anteriores
- 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
Continuemos...
Código Olor 106 - Código dependiente de la producción
No agregue IF para verificar el entorno de producción.
TL; DR: evite agregar condicionales relacionados con la producción
Problemas
- Violación del principio de fallo rápido
- Falta de capacidad de prueba
Soluciones
- Si es completamente necesario, modele entornos y pruébelos TODOS .
Contexto
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í.
Código de muestra
Equivocado
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]>
Derecha
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]>
Detección
- [x] manuales
Este es un olor de diseño.
Necesitamos crear configuraciones de desarrollo/producción vacías y delegarlas con objetos polimórficos personalizables.
Etiquetas
- Acoplamiento
Conclusión
Evite agregar condicionales no comprobables.
Crear configuraciones delegando reglas de negocio.
Utilice abstracciones, protocolos e interfaces, evite jerarquías estrictas.
Relaciones
Code Smell 56 - Preprocesadores
Más información
Créditos
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
Code Smell 107 - Reutilización de variables
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
Problemas
- Legibilidad
- Problemas ocultos
Soluciones
- No reutilices variables
- Método de extracción para aislar ámbitos
Contexto
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.
Código de muestra
Equivocado
// 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
Derecha
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 ); }
Detección
- [ ] Automático
Linters puede usar el árbol de análisis para encontrar definiciones y usos de variables.
Etiquetas
- Legibilidad
Conclusión
Evite reutilizar nombres de variables. Use nombres más específicos y diferentes.
Relaciones
Code Smell 03 - Las funciones son demasiado largas
Más información
Refactorización 002 - Método de extracción
Créditos
Simplicidad antes que generalidad, uso antes que reutilización.
kevlin henney
Grandes citas de ingeniería de software
Code Smell 108 - Afirmaciones flotantes
Afirmar que dos números flotantes son iguales es un problema muy difícil
TL;DR: No compares flotadores
Problemas
- Resultados de prueba incorrectos
- Pruebas frágiles
- Violación del principio de fallo rápido
Soluciones
- Evite los flotadores a menos que tenga preocupaciones REALES sobre el rendimiento
- Usar números de precisión arbitraria
- Si necesita comparar flotadores, compare con la tolerancia.
Contexto
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.
Código de muestra
Equivocado
Assert.assertEquals(0.0012f, 0.0012f); // Deprecated Assert.assertTrue(0.0012f == 0.0012f); // Not JUnit - Smell
Derecha
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
Detección
- [ ] Automático
Podemos agregar una verificación con assertEquals() en nuestros marcos de prueba para evitar la verificación de flotadores.
Etiquetas
- Prueba de olores
Conclusión
Siempre debemos evitar comparar flotadores.
Relaciones
Code Smell 71 - Flotadores mágicos disfrazados de decimales
Más información
Créditos
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
Olfato de código 109 - Propiedades automáticas
¿Qué pasa si combinas 4 olores de código?
TL;DR: Evitar Getters, Evitar Setters, Evitar Metaprogramación. Piensa en el Comportamiento.
Problemas
- Violación de ocultación de información
- Mutabilidad
- Violación del principio Fail Fast
- Código duplicado al establecer propiedades
Soluciones
Contexto
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.
Código de muestra
Equivocado
class Person { public string name { get; set; } }
Derecha
class Person { private string name public Person(string personName) { name = personName; //imutable //no getters, no setters } //... more protocol, probably accessing private variable name }
Detección
- [ ] Automático
Esta es una característica del lenguaje.
Debemos evitar lenguajes inmaduros o prohibir sus peores prácticas.
Etiquetas
- Encapsulación
Conclusión
Necesitamos pensar cuidadosamente antes de exponer nuestras propiedades.
El primer paso es dejar de pensar en propiedades y centrarse únicamente en el comportamiento.
Relaciones
Code Smell 70 - Generadores de modelos anémicos
Code Smell 01 - Modelos anémicos
Más información
- escuelas W3
- Pereza I - Metaprogramación
- Pereza II - Asistentes de código
- Refactorización 001 - Eliminar setters
- El poder maligno de los mutantes
- Fallar rapido
Créditos
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
Code Smell 110 - Interruptores con valores predeterminados
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.
Problemas
- Acoplamiento
- Violación del principio Fail Fast
- Violación del principio abierto cerrado
Soluciones
- Reemplazar si y casos con polimorfismo
- Cambiar el código predeterminado a una excepción
Contexto
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.
Código de muestra
Equivocado
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; }
Derecha
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; }
Detección
- [x] Semiautomático
Podemos decirle a nuestros linters que nos adviertan sobre los usos predeterminados a menos que haya una excepción.
Etiquetas
- Fallar rapido
Conclusión
Escribir código robusto no significa que debamos tomar decisiones sin evidencia.
Relaciones
Code Smell 36 - Declaraciones Switch/case/elseif/else/if
Más información
Créditos
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!