Upload
thoughtbot
View
392
Download
0
Embed Size (px)
DESCRIPTION
Slidedeck for the Refactoring Workshop given at RubyConf Argentina 2014 rubyconfargentina.org
Citation preview
4 recetas para simplificar tu código
git clone http://github.com/tute/refactoring-workshop
¡Buen día!
1. ¿Cómo te llamás? 2. ¿Sos nuevo/nueva programando? 3. ¿Cuánto tiempo llevás programando en Ruby?
Aprenderemos a transformar esto…
En esto!
Patrones de Refactorización
Eufemismo para “No vas a creer cómo simplificamos
esta masa de código en 5 sencillos pasos”
Hoy veremos
Sobre mi
Sobre mi
Sobre mi
Sobre mi
Sobre mi
2011/2012: Chef Surfing
• No parábamos de programar
• La complejidad nos bloqueaba c/ 2 meses
• Parábamos. Testéabamos. Refactorizábamos.
• No era predecible.
Sobre mi
2011/2012: Chefsurfing
Sobre mi
2013: General Assembly
• Rails app en malas condiciones
• Pero con buenos tests
• Me dijeron “refactorizá lo que quieras”
• Agilizó el trabajo, semana tras semana
• Quiero repetir (y mejorar) esta historia
Sobre mi
2013: General Assembly
Sobre mi
2014: thoughtbot
• Calidad del código es el pan de cada día
• Priorizamos agresivamente qué desarrollar
• Escribimos lo mejor posible siempre
• No se acepta deuda técnica
• Programadores y clientes felices
Sobre mi
2014: thoughtbot
Patrones de Refactorización
1. Método que revela la intención
2. Objeto de "Caso Especial"
3. Reemplazar método con Objeto Método
4. Objeto "Servicio"
Hoy veremos
1/4 Método que revela la intención
Método que revela la intención
Porqué se llama es más importante que qué, o cómo, se hace.
Método que revela la intención
1/4 Método que revela la intención
“Planché la camisa y me afeité” (qué)
“Puse la camisa sobre la remera que me regaló mi tía, y pasé una afeitadora por mi cara” (cómo)
“Me preparé para salir” (porqué)
1/4 Método que revela la intención
# Remove duplicates?if hash[row[1]][date] != row[0] # ...
if remove_duplicates?(row, date) # ...
def remove_duplicates?(row, date) hash[row[1]][date] != row[0]
Un Algoritmo
1/4 Método que revela la intención
1. Agregar comentarios si son necesarios
2. Transformar comentarios en métodos
3. Los comentarios son ahora código
4. El código se auto-describe
¿“No más de 5 líneas por método”?
1/4 Método que revela la intención
¡No hay problema!
El patrón más sencillo
1/4 Método que revela la intención
y difícil a la vez
Sin Tests no hay refactorización
O van a tener que escuchar, con razón, “no arregles lo que no está roto”
Prerequisito: hay tests
Prerequisito: hay tests
¡Estos karting van a 200!
Prerequisito: hay tests
Parece que este 747 no se mueve.
Sens
ació
n de
Vel
ocid
ad
0
50
100
150
200
Velocidad Real
0 250 500 750 1000
747
Kart
Prerequisito: hay tests
Prerequisito: hay tests
Sens
ació
n de
Vel
ocid
ad
0
50
100
150
200
Velocidad Real
0 250 500 750 1000
TDD-refactor
Deploy!
Objeto de Caso Especial (Nulo)
2/4 Objetos de Caso Especial
El objeto más común del mundo Ruby:
nil
Problema 1: origen de nil
2/4 Objetos de Caso Especial
session[:current_user] # => nil session[:current_uzer] # => nil if (false) then 1 end # => nil empty_method() # => nil
Problema 1: origen de nil
2/4 Objetos de Caso Especial
Undefined method `title' for nil:NilClass
¿Viene de un blog post, un producto, o una noticia?
2/4 Objetos de Caso Especial
def blog_post Post.find(params[:id]) || :no_post end blog_post.title
Undefined method `title' for no_post:Symbol
Problema 1: mejor retornar un símbolo
Problema 2: condicionales
2/4 Objetos de Caso Especial
if blog_post “Ver #{blog_post.title}” else ‘Ver todos los posts' end
Más imperativo que orientado a objetos.
Fácil de olvidar.
Solución: retornar un Objeto
2/4 Objetos de Caso Especial
class NullPost def title; “todos”; end end
def blog_post Post.find(params[:post_id]) || NullPost.new end
“Ver #{blog_post.title}” # WIN
3/4 Reemplazar Método con Objeto Método
def row_per_day_format(file_name) file = File.open file_name, 'r:ISO-8859-1' # hash[NivelConsistencia][date] = [[value, status]] hash = { '1' => {}, '2' => {} } dates = [] str = ''
CSV.parse(file, col_sep: ';').each do |row| next if row.empty? next if row[0] =~ /^\/\// date = Date.parse(row[2]) (13..43).each do |i| measurement_date = date + (i-13)
# If NumDiasDeChuva is empty it means no data
3/4 Reemplazar Método con Objeto Método
Reemplazar Método con Objeto Método
1. Crear una clase con los mismos argumentos de inicialización que el método
2. Copiar y pegar el método en la nueva clase, sin argumentos
3. Reemplazar el método original con un llamado a la nueva clase
4. Aplicar “Método que Revela la Intención”. Voilà.
1. Nueva clase con mismos argumentos
class FormatAtoB def initialize(file_name) @file_name = file_name end end
3/4 Reemplazar Método con Objeto Método
2. Copiar y pegar el cuerpo
class FormatAtoB def initialize(file_name) @file_name = file_name end
def row_per_day_format file = File.open file_name, 'r:ISO-8859-1' # …
3/4 Reemplazar Método con Objeto Método
3. Reemplazar llamada original
def row_per_day_format(file_name) FormatAtoB.new(file_name). row_per_day_format end
3/4 Reemplazar Método con Objeto Método
4. Aplicar “Método que Revela la Intención”
class FormatAtoB def initialize(file_name) @file_name = file_name end
def row_per_day_format load_file_a format_data end …
3/4 Reemplazar Método con Objeto Método
3/4 Reemplazar Método con Objeto Método
Reemplazar Método con Objeto Método
1. Crear una clase con los mismos argumentos de inicialización que el método
2. Copiar y pegar el método en la nueva clase, sin argumentos
3. Reemplazar el método original con un llamado a la nueva clase
4. Aplicar “Método que Revela la Intención”. Voilà.
Objetos Servicio
Decoupling different concerns from chubby classes
4/4 Objetos Servicio
Si agregamos nueva funcionalidad a un objeto existente
• Se acopla a nuevas dependencias
• Pierde cohesión
• Los tests se tornan más complejos y lentos
• La descripción del objeto incluye “y"/"o" (SRP)
4/4 Objetos Servicio
Modelando nuevo comportamiento
4/4 Objetos Servicio
• Si fuera un concepto del dominio del problema es un nuevo Modelo (una Entidad).
• Si es sólo un proceso o algoritmo (sin estado),es un nuevo Servicio.
Términos del libro “Domain Driven Design”.
4/4 Objetos Servicio
Modelando nuevo comportamiento
Próximos Pasos
• Envíen Pull Requests en GitHub
• Es una mina de oro para enseñar y aprender
• Eligen proyectos y mentores como en un supermercado eligen galletitas
Próximos Pasos
Próximos Pasos: las 4 reglas
• Clases de a lo sumo 100 líneas
• Métodos de a lo sumo 5 líneas
• Métodos con 4 argumentos como máximo
• Un controlador instancia sólo una variable de instancia
Próximos Pasos
Porqué Refactorizar
No sólo sobre estética (aunque es consecuencia)
También conocimiento compartido,encontrar bugs, y performance.
Próximos Pasos
Porqué Refactorizar
Trabajamossobre las herramientas con que trabajamos.
Somos usuarios y creadores.
Próximos Pasos
Porqué Refactorizar
Si tengo un sesgo, elijo “over-engineering".
Porque “Under-engineering” es caro, riesgoso y superpoblado.
Próximos Pasos
¡Gracias!
Preguntas bienvenidas.