Buenas Prácticas de desarrollo en Ruby on Rails - Presentation Transcript
Buenas prácticas
de desarrollo en
Ruby on Rails
Sergio Gil Pérez de la Manga
Súper Mega Disclaimer
Todo el contenido de esta charla se
basa en opiniones personalísimas
del autor, salvo cuando se citen
expresamente las opiniones de otros
autores, en cuyo caso se trata de
interpretaciones personalísimas de
las mismas
Súper Mega Disclaimer
Lo que tenga un asterisco gordo al
lado, es que no me lo he inventado
(y está en la lista de referencias)
“Best Practice is an idea that asserts that
there is a technique, method, or process
that is more e ective at delivering a
particular outcome than any other
technique, method or process”
“En el Go todas las piezas
son iguales; en el Ajedrez,
son diferentes, y obedecen
a reglas de desplazamiento
distintas, lo que complica
el aprendizaje de la regla,
pero facilita la tarea del
debutante: un cuadro de
juego codificado es de un
uso más sencillo que una
libertad completa con la
que no se sabe qué hacer”
Pierre Aroutche ,
“El Go”
Cosas de las que no voy
a hablar (por obvias)
TESTING
Código
Buen
fácil de
Código
testear
Refactorizar sin
tests es un deporte
de riesgo
Control de Versiones
Infórmate, participa, interactúa
LEE
LEE
Documentación
LEE
Documentación
Blogs
LEE
Documentación
Blogs
Listas de correo
ESCRIBE
Documentación
Blogs
Listas de correo
Acude a Conferencias
Acude a Conferencias
¡Y habla si te dejan!
Ven a las quedadas
Haz pair programming si puedes
Hablemos de código
Conoce tus herramientas
some_things = []
some_other_things.each do |some_other_thing|
some_things << some_other_thing.wadus
end
some_things = some_other_things.map do |some_other_thing|
some_other_thing.wadus
end
some_things = some_other_things.map(&:wadus)
DRY pero no tanto
Don’t Repeat Yourself
“Every piece of knowledge must have
a single, unambiguous, authoritative
representation within a system”
Pero DRY es un medio, no un fin
Pero DRY es un medio, no un fin
Lo único importante es:
Pero DRY es un medio, no un fin
Lo único importante es:
Legibilidad
Pero DRY es un medio, no un fin
Lo único importante es:
Legibilidad
Mantenibilidad
login: &login
adapter: mysql
username: username
password: password
host: mysql.example.com
Pero DRY es un medio, no un fin development:
<<: *login
Lo único importante es:
database: app_dev
Legibilidad
Mantenibilidad test:
<<: *login
database: app_test
production:
<<: *login
database: app_prod
MVC
Skinny Controller,
Fat Model
Modelo cocinero,
controlador camarero
class Person < AR::B
has_one :address
end
class PeopleController < AC
end
<% people = Person.find(
:conditions => [\"added_at > ? and deleted = ?\", Time.now.utc, false],
:order => \"last_name, first_name\") %>
<% people.reject { |p| p.address.nil? }.each do |person| %>
<div class=\"person\">
<span class=\"name\">
<%= person.last_name %>, <%= person.first_name %>
</span>
<span class=\"age\">
<%= (Date.today - person.birthdate) / 365 %>
</span>
</div>
<% end %>
class Person < AR::B
has_one :address
end
class PeopleController < AC
def index
@people = Person.find(
:conditions => [\"added_at > ? and deleted = ?\", Time.now.utc, false],
:order => \"last_name, first_name\")
@people = @people.reject { |p| p.address.nil? }
end
end
<% @people.each do |person| %>
<div class=\"person\">
<span class=\"name\">
<%= person.last_name %>, <%= person.first_name %>
</span>
<span class=\"age\">
<%= (Date.today - person.birthdate) / 365 %>
</span>
</div>
<% end %>
class Person < ActiveRecord::Base
has_one :address
def self.find_recent
people = find(
:conditions => [\"added_at > ? and deleted = ?\", Time.now.utc, false],
:order => \"last_name, first_name\")
people.reject { |p| p.address.nil? }
end
def name
\"#{last_name}, #{first_name}\"
end
def age
(Date.today - person.birthdate) / 365
end
end
class PeopleController < ActionController::Base
def index
@people = Person.find_recent
end
end
<% @people.each do |person| %>
<div class=\"person\">
<span class=\"name\"><%= person.name %></span>
<span class=\"age\"><%= person.age %></span>
</div>
<% end %>
Hacia el controlador trivial
Hacia el controlador trivial
Plugins como resource_controller
Hacia el controlador trivial
Plugins como resource_controller
class PostsController < ApplicationController
resource_controller
end
REST
RESTricción liberadora
Si lo que quieres hacer no encaja en REST
Si lo que quieres hacer no encaja en REST
• Puede que pertenezca al 20% de
cosas que no encajan
Si lo que quieres hacer no encaja en REST
• Puede que pertenezca al 20% de
cosas que no encajan
• Puede que lo estés enfocando mal
Si lo que quieres hacer no encaja en REST
• Puede que pertenezca al 20% de
cosas que no encajan
• Puede que lo estés enfocando mal
• Así que dale una vuelta
Demeter y el Acoplamiento
Un método de un objeto sólo
debe llamar a:
Un método de un objeto sólo
debe llamar a:
• Métodos del mismo objeto
Un método de un objeto sólo
debe llamar a:
• Métodos del mismo objeto
• Métodos de objetos
directamente relacionados
class User < AR::B
# email
end
class Blog < AR::B
belongs_to :user
has_many :articles
end
class Article < AR::B
belongs_to :blog
end
article.blog.user.email
class User < AR::B
# email
end
class Blog < AR::B
belongs_to :user
has_many :articles
delegate :email, :to => :user
end
class Article < AR::B
belongs_to :blog
delegate :email, :to => :blog
end
article.email
El termómetro del test
before(:each) do
@country = mock_model(Country, :two_letter_code => 'es')
@city = mock_model(City, :country => @country)
@address = mock_model(Address, :city => @city)
@author = mock_model(User, :address => @address)
@article = mock_model(Article, :author => @author)
@comment = mock_model(Comment, :article => @article)
end
it \"should have two_letter_code 'es'\" do
@comment.article.author.adress.city.country.two_letter_code.should == 'es'
end
El termómetro del test
before(:each) do
@comment = mock_model(Comment, :author_country_code => 'es')
end
it \"should have two_letter_code 'es'\" do
@comment.author_country_code.should == 'es'
end
Uso de convenciones
Las de Rails: piénsatelo antes de saltártelas
Crea las tuyas propias
Crea las tuyas propias
¡Y cúmplelas!
Refactorización
Refactoriza durante el desarrollo...
...y no al final
1. No refactorices y añadas
funcionalidad a la vez
1. No refactorices y añadas
funcionalidad a la vez
2. Haz tests antes de refactorizar.
Y ejecútalos a menudo
1. No refactorices y añadas
funcionalidad a la vez
2. Haz tests antes de refactorizar.
Y ejecútalos a menudo
3. Refactoriza en pasos pequeños
Uso de variables
Minimizar uso de variables, y su scope
def show
@post = Post.find(params[:id])
@related_posts = Post.find(:all,
:conditions => { :category_id => @post.category_id },
:limit => 5)
end
<h2><%= @post.title %></h2>
<%= simple_format(@post.body) %>
<%- @recent_posts.each do |post| -%>
...
<%- end -%>
Minimizar uso de variables, y su scope
def show
@post = Post.find(params[:id])
@related_posts = @post.recent_posts
end
<h2><%= @post.title %></h2>
<%= simple_format(@post.body) %>
<%- @recent_posts.each do |post| -%>
...
<%- end -%>
Minimizar uso de variables, y su scope
def show
@post = Post.find(params[:id])
end
<h2><%= @post.title %></h2>
<%= simple_format(@post.body) %>
<%- @post.recent_posts.each do |post| -%>
...
<%- end -%>
Minimizar uso de variables, y su scope
Minimizar uso de variables, y su scope
Mi convención:
Minimizar uso de variables, y su scope
Mi convención:
Una variable de instancia por acción
Minimizar uso de variables, y su scope
Mi convención:
Una variable de instancia por acción
• Instancia de un
modelo
Minimizar uso de variables, y su scope
Mi convención:
Una variable de instancia por acción
• Instancia de un
modelo
• Nombrada como el
modelo
Minimizar uso de variables, y su scope
Mi convención:
Una variable de instancia por acción
• Instancia de un • Array de instancias
modelo de un modelo
• Nombrada como el
modelo
Minimizar uso de variables, y su scope
Mi convención:
Una variable de instancia por acción
• Instancia de un • Array de instancias
modelo de un modelo
• Nombrada como el • Nombrada como el
modelo modelo en plural
El idioma del código
• Se trata de
intercambiar, ¿no?
• Se trata de
intercambiar, ¿no?
• Rails hace un gran
esfuerzo por acercarse
al lenguaje humano. Si
escribimos en
spanglish, nos lo
cargamos
• Se trata de
intercambiar, ¿no?
• Rails hace un gran
esfuerzo por acercarse
al lenguaje humano. Si
escribimos en
spanglish, nos lo
cargamos
has_many :legajos
Referencias
Pierre Aroutche , “El Go”
Andrew Hunt, Dave Thomas, “The Pragmatic Programmers”
Andrew Hunt, Venkat Subramaniam, “Practices of an Agile Developer”
Martin Fowler, “Refactoring: Improving the Design of Existing Code”
http://en.wikipedia.org/wiki/Best_practices
http://en.wikipedia.org/wiki/Law_of_Demeter
http://www.ccs.neu.edu/home/lieber/LoD.html
http://brian.maybeyoureinsane.net/blog/2006/12/15/law‐of‐demeter‐or‐how‐to‐avoid‐coding‐yourself‐into‐a‐corner‐in‐rails/
http://weblog.jamisbuck.org/2006/10/18/skinny‐controller‐fat‐model
http://c2.com/cgi/wiki?DontRepeatYourself
Enjuto Mojamuto en:
“Debuggeando una aplicación sin tests”
Caca
de bug
Como Se Fue Vino™
0 comments
Post a comment