Este documento discute la importancia de mantener un alto nivel de calidad en el código a través del refactoring. Se mencionan varias métricas y "code smells" que pueden indicar problemas en el diseño del código y se proponen soluciones como extraer clases, mover métodos y utilizar patrones de diseño para mejorar la legibilidad, mantenibilidad y capacidad de extensión del código. También enfatiza la necesidad de invertir tiempo y recursos en refactoring para prevenir problemas a futuro y mantener un código de alta calidad.
4. • CTO @ MagmaLabs
• Evangelista de OpenSource
• Conferencista
• Programador por mas de 15 años
• Ha tirado producción
• Trabajado en sitios de alto desempeño y equipos multidisciplinarios, para
clientes tipo: Google, GE, GoPro.
• @softr8 everywhere!
¿Quién soy?
5. Startups that prioritize feature
velocity over quality tend to survive.
This is deeply offensive to many
software developers.
https://mailchi.mp/railsspeed/on-quality-and-performance-at-early-stage-startups
7. – Todos los programadores en algún punto
“Mi código es lo mejor del mundo”
8. • Facilmente extendible
• Pruebas unitarias
• Escrito para humanos, no para computadoras
• Auto-descriptivo
• Fácilmente transferible a otra persona
• Sin mensajes ocultos
Cualidades de un buen código
9. ¿Se puede medir la calidad cuantitativamente?
Claro! Hay herramientas que te ayudan
10. • Incidentes en Producción
• Tiempo de ideación a liberación
• Código real necesario
• Código ejecutado por las pruebas automatizadas
Métricas para medir calidad del código
11. • Complejidad ciclomática
• Cuantos caminos de ejecución se crean, mayor numero menor calidad
• Complejidad esencial
• Que tanto código se puede reescribir para eliminar multiples caminos de
ejecución
• Densidad ciclomática
• Radio del numero total de lineas de código entre el numero de puntos de
desiciones lógicas
Métricas para medir calidad del código
12. • Numero de clases, hasta 6 niveles de herencia
• Número de métodos por clase, no más de 20
• Número de lineas de código por método, no más de 10
• Número de desiciones por método, no más de 2
• Responsabilidades por objeto, solo deben hacer una sola cosa
• Formato de código
Métricas para medir calidad del código
23. –Martin Fowler
“A code smell is a surface indication that usually
corresponds to deeper problem in the system.”
24. – Kent Beck
“A code smell is a hint that something has gone wrong
somewhere in your code. Use the smell to track down
the problem.”
25. • No necesariamente son Bugs
• El código tecnicamente está correcto
• No previenen al código actual de hacer su función
• Síntoma de que pudiera existir areas que generan preocupaciones
Code Smell
26. “Code smells simplemente indican fallas en el diseño que
pueden alentar el desarrollo y mantenimiento de software.”
27. • No legible
• Duplicado
• Complejo
• Difícil de modificar
Código Malo
30. • Una sola clase tratando de hacer demasiado
• Muy general, no aplican el principio de responsabilidad única
• Solución:
• Extraer la clase en funcionalidades aisladas
• Extraer a subclases con polimorfismo
Large Class
32. • Heredado de programación procedural, utiliza todos los que ocupes!
• Con POO, se reduce la necesidad
• Solución
• Pasar objetos en vez de parámetros
• El objeto pasado es quien tiene toda información
• Quien lo recibe usa solo la información necesaria
Long Parameter List
34. • Una clase cambia en diferentes maneras por diferentes razones
• ¿Pareciera dos objetos en una sola clase?
• Todos los cambios parecen ir a una sola clase?
• Solución:
• Extraer a otra clase
Divergent Change
35. • Objetos deben empaquetar solo información usada por si mismos
• Objetos muy interesados en datos o métodos de una clase externa en
específico
• Solución:
• Mover metodos
• Regresar objetos en vez de primitivos
Feature Envy
36. Feature Envy
class Warehouse
def sale_price(item)
item.final_price * @vat
end
end
class Item
def final_price
price - rebate
end
end
37. • Algunos datos parecen ‘siempre ir’ juntos
• Ejemplos:
• Propiedades en clases
• Mismos parametros en diferentes funciones
• Solución
• Extraer datos comunes en objetos
• Objetos en parametros
• Enviar el objeto completo en vez de dus propiedades
Data Clumps
38. Data Clumbs
class Dummy
attr_reader :x1, :y1
def initialize(x1, y1)
@x1 = x1
@y1 = y1
end
def x ; x1 * y1 end
def y ; x1 / y1 end
def z ; x1 - y1 end
end
39. • Codigo muy parecido en multiples lugares
• Externamente no se parece, pero internamente si
• Solución:
• Utility classes
• Herencia
Duplicated Code
41. • No es código ‘orientado a objetos”
• Se debería usar polimorfismo en su lugar
• Solución:
• Switches representan un ‘tipo’ de código
• Cada ‘tipo’ debería corresponder a una clase
• Factory Pattern
Switch statements
42.
43. • ¿Pareciera que la clase no tiene porque estar ahi?
• Se planearon cambios a esa clase pero no se necesitaron
• Se encoge cuando se hace refactor
• No pareciera valer la pena
• Solución
• ¿Utility class?
Lazy Class
44. • No siempre son mala señal
• No se usen como desodorante!
• Refactor este tipo de smell generalmente termina en removiendo el código
• Revisar si el comentario es necesario, si no, removerlo
• Solución:
• Comentar usando formatos estándar de documentación en linea
• Agregar un TODO con criterios cuando se removera
Comments
45. • Algo anda mal
• No se parece en nada, totalmente fuera de contexto
• Solución:
• Utility Class
Black Sheep
46.
47. • Generalmente se mezclan abstracciones y llamadas
• Ejecución de código procedural y llamadas a funciones
• Solución
• Estandarizar llamadas a funciones o código procedural
Mixed levels of abstraction
49. • Una nueva implementación involucra muchas modificaciones en diferentes
lugares
• Firmas de funciones se necesitan ser actualizadas
• Difícil saber que tanto se necesita modificar
• Solución
• Abstraer llamadas en objetos
• Si no se encuentra un buen lugar para mover los objetos, a crearlos!
Shotgun Surgery
50. • Como su nombre lo indica, se usan boleanos como parámetros
• Solución, eliminarlos desde la llamada
Boolean Parameter
52. • Variables de uso global
• Difícil encontrar donde se inicializa el valor
• Solución
• Config classes
• Singletons
Class Variable
53. • Misma condicional usada en multiples lugares
• Causa de una mala implementación de polimorfismo
• Solución:
• Abstracción
• Mejor Polimorfismo
Repeated Conditional
54. • Acarreándose de diseño original
• No se actualizaron firmas de las funciones
• Solución
• Remover el parametro y todas sus llamadas
• Usar una convención para denotar los parámetros no usados _noUsado
Unused parameters
55. • Se crearon metodos privados que ya no se utilizan
• Generan carga cognitiva
• Causa de clases grandes
• Solución
• Eliminarlos
Unused Private Methods
56. • Una función utilitaria es aquella que no necesita almacenar estados para
generar resultados
• Solución
• Crear métodos estáticos
Utility Function
57. • Escribir código
• Asegurar pruebas verdes
• Pedir revision
• Aceptar comentarios y mejorar el código
• Escoger el área más grave
• Aplicar refactor
Que debemos hacer
66. • Presupuesto
• Si no se hace desde un inicio, esta pidiendo un préstamo pagando lo mínimo
• Refactor es abonar pagos al préstamo y bajar la tasa de interés
• No invertir en refactor es aceptar irse al buró de crédito
Se necesita tiempo para mantener buen código