16 AprLa búsqueda de la satisfacción

Friday, 16 April 2010 — 09:52

No hacen falta 3 años de carrera, para darse cuenta que los comportamientos del ser humano, pueden englobarse, de forma general, por la búsqueda de la satisfacción, o su versión superlativa, el placer. Si tenemos esto presente, lo podemos aplicar a todos los ámbitos de la vida, con el propósito de ser mas eficientes, mejorar nuestros procesos productivos, entender a la gente, incluso ser mejores personas.

La satisfacción generalmente, se obtiene por la consecución de un reto. Cuanto mayor sea la dificultad del mismo, mayor la satisfacción. Los extremos son siempre peligrosos. Los retos de dificultad maxima, de difícil consecución, pueden producir el efecto contrario, la frustración. Mientras que los retos de dificultad ínfima, generan satisfacción en la misma medida. Por lo tanto, como siempre, el equilibrio esta en el término medio.

Esta teoría da explicación a muchos de los comportamientos de nuestra sociedad actual. El ser humano se mueve por la búsqueda de la satisfacción. Ante una disyuntiva, la elección será siempre aquella que produzca mayor satisfacción, con el menor esfuerzo posible para llegar a ella (superar un reto).

Como decía en la introducción, la teoría es aplicable a varios ámbitos de nuestra vida. Uno de ellos, el de ser mas eficientes en nuestros quehaceres diarios.

Existen muchas metodologías de trabajo, que básicamente estipulan el tiempo de trabajo continuado, el tiempo de descanso, y sobre todo la organización y consecución de las tareas. Esta ultima, a mi modo de entender, es la clave del éxito, ya que no todas las personas soportan o necesitan las mismas horas de trabajo o descanso. Aquí tenéis el proceso:

1. Define el tiempo efectivo del que dispones
2. Tomate tu tiempo para dividir las grandes tareas, en tareas mas pequeñas. El tiempo estimado de una tarea no puede ser nunca, superior a dos horas. Por encima de ese tiempo, y si aparecen problemas, aparece la frustracion por no ser productivos, y haber perdido mas de dos horas en el intento.
3. Crea una lista ordenada por prioridad, junto al tiempo estimado de realización de cada una.
4. Traza una linea divisora en la tarea que cae dentro del tiempo definido en 1.
5. Del grupo de tareas establecido en 4, mueve hacia arriba aquellas tareas cuya realización se estima inferior a 10 minutos.
6. Toma la primera de la lista, y olvida el resto hasta su consecucion.

Solo si aparece una nueva tarea, o cambia la estimación de tiempo de una tarea, debes tomarte de nuevo tu tiempo en rehacer la lista siguiendo el proceso de 1 a 6. Una vez restablecida, vuelve a la primera tarea de la lista, como si fuera la única. Es importante que la lista la tengais oculta mientras trabajáis. Así evitareis saltar de una tarea a otra (gran error), o agobiarse con todas las tareas que hay que hacer. Por mas que la miréis, las tareas no se van a hacer solas.

De acuerdo a la teoría inicial, el reto es la tarea en si misma, mientras que la satisfacción nos viene por la consecución de las tareas. De esta forma, nunca acabareis el día pensando que no habéis sido productivos, y comprobareis que sois mas eficientes, ademas de sentiros mejor. Haced la prueba!. Ah, no hemos hablado del descanso. Y es que creo que todos, sabemos cuando necesitamos descansar… o no?. Bueno, donde tenéis vuestra lista?

Ger

31 Mar"Ruby" or FRuby?. Part I

Wednesday, 31 March 2010 — 08:59

ActiveRecord comes with a bunch of very useful utilities for retrieving data from your database. This is really helpful for developers without knowledge on databases. We can get data from the database using very simple commands like:

last_post = Post.find(:last)
first_post = Post.first
Post.find(:all, :conditions => "type='aType'",:limit => 5)

If you have a DBA on your team, i’m sure you will have some disputes about using Ruby, or what they call FRuby (do i need to explain what does the F means?)

All those ActiveRecord utilities are translated at the end on SQL queries, and that’s why they think we should get rid of ActiveRecord’s methods and use simple queries. ActiveRecord comes with a find_by_sql query where you just enter the query to be applied, as well as the ActiveRecord::Base.connection.execute method:

Post.find_by_sql "SELECT p.* from posts where type='aType' limit 5"

Ruby on Rails works really nice on some circumstances and what’s more, the code is really simple to read. named_scope makes our life much easier and the code much more readable than using sql queries.

#post.rb
named_scope :of_type, lambda{|post_type|
    post_type ? {:conditions =>"posts.type = #{post_type}"} : {}}
named_scope :limit, lambda { |limit| {:limit => limit}}

#posts_controller.rb
Post.of_type('aType').limit(5)

Of course this is a very simple example, but where you will really see the difference, is using associations:

#employee.rb
has_many :kids

#kids
belongs_to :school

#employees_controller
@employee.kids.map(&:school).compact #returns schools where the employee takes his children

As you guess, that will get more complicated with sql:

SELECT * from SCHOOLS s join KIDS k on k.school_id = s.id join EMPLOYEES e on e.id = k.employee_id where e.name="andrew"

and this is still readable, but i’m sure things can get more and more complicated. So there is the question, ruby, or FRuby. What would you think is faster?

29 MarConvert a Hash to xml

Monday, 29 March 2010 — 07:01

When we get a request in our controller, we use to get request information from “params” parameter in a hash object. Thus, it’s simple for example to get information sent through something simple like:

info_hash = params[:post]

In some cases, usually when we want to send to the server a big amount of information, we usually use an xml. Rails converts this xml into a hash form so that we can deal more easily with it. Let’s imagine we get this hash in our controller:

>> test = {"uno"=>["dos"=>"dos_uno","cuatro"=>"cuatro_uno"], "zero"=>"zero_one"}=> {"uno"=>[{"cuatro"=>"cuatro_uno", "dos"=>"dos_uno"}], "zero"=>"zero_one"}

And now what if you want to convert that hash to xml?. Rails gives a very simple built in solution for this through vendor/rails/activesupport/lib/active_support/core_ext/array/conversions.rb:

test.to_xml(:skip_types => true,:dasherize => false, :indent => 0, :root => "training")=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?><training><uno><uno><cuatro>cuatro_uno</cuatro><dos>dos_uno</dos></uno></uno><zero>zero_one</zero></training>"

As you can see, it has created nested elements, but there is one thing i don’t like in this case, and that’s the extra element “uno”. How can we get rid of it?

Another way for doing this, is using another built in library from Rails, like XmlSimple. It has two methods, xml_in, and xml_out. We will use xml_out in this case, with AttrPrefix set to true. You can check some more options here:

XmlSimple.xml_out(test, "AttrPrefix"=>true)=> "<opt>\n  <uno>\n    <cuatro>cuatro_uno</cuatro>\n    <dos>dos_uno</dos>\n  </uno>\n  <zero>zero_one</zero>\n</opt>\n"

You can use some other options to customize your output but at least we managed to remove the extra level. Nice!.

In any case, if you just wanted to get the submitted xml, you’d better use this instead :-)

submitted_xml = request.body

26 Marattr_accessible and mass-assignment

Friday, 26 March 2010 — 23:31

It’s always a good practice to use attr_accessible in your models, to protect sensible attributes from being filled through the technique known as mass-assignment. With mass-assignment we understand methods such as: new(attributes), update_attributes(attributes), or attributes=(attributes), that allow us to create new records very easily.

So, on one side, we can keep skinny controllers using mass-assignment, but on the other side, we can create a vulnerability in our code for hackers, to inject sensitive information in our models, like passwords, user admins, owner and so on…

From API doc, here is a clear example:

class Customer < ActiveRecord::Base
    attr_accessible :name, :nickname
  end

  customer = Customer.new(:name => "David", :nickname => "Dave", :credit_rating => "Excellent")
  customer.credit_rating # => nil. Not accessible
  customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb" }
  customer.credit_rating # => nil. Not accessible

  customer.credit_rating = "Average"
  customer.credit_rating # => "Average", It is accessible

It can be tedious, as you need to add all accessible methods there, or you will get:

WARNING: Can't mass-assign these protected attributes

But even with that, attr_accessible should be the way to go. If you have a long list of items, you can use attr_protected instead. BUT there is one more thing to take into account.

When you add attr_accessible to your models, ActiveRecord will protect it from mass-assignment as expected, but will also remove not acceptable attributes on mass-assignment. Let’s continue with previous Customer class example:

customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb", :non_existing_attr =>"whatever" }

and this returns:

WARNING: Can't mass-assign these protected attributes: non_existing_attr

but it’s just a warning. If we remove the attr_accessible line from the model, we will get a NoMethodError exception instead:

NoMethodError: undefined method `non_existing_attr='

The reason is in ActiveRecord. When we call attributes=, and we have attr_accessible/attr_protected set, this is executed:

attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
...

def remove_attributes_protected_from_mass_assignment(attributes)
..
attributes.reject { |key, value| !self.class.accessible_attributes.include?(key.gsub(/\(.+/, "")) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
...
end

So to sum up, those params not in attr_accessible are removed, and you will never get an exception. Take this into account when you use attr_accessible

16 MarRails associations and interlock finders

Tuesday, 16 March 2010 — 08:45

If you are using Interlock from Evan Weaver in your Rails project, this post might be of your interest. As you can see from the code, Interlock caches all those requests using find, find_by, find_all_by_id. From Evan Readme notes:

Now, whenever you call find, find_by_id, or find_all_by_id with a single id or an array of ids, the
cache will be used. The cache key for each record invalidates when the record is saved or destroyed. Memcached’s multiget mode is used for maximum performance.

If you pass any parameters other than ids, or use dynamic finders, the cache will not be used. This means that
:include works as expected and does not require complicated invalidation

I was fighting recently with a memcache problem on a project that used a customized version of interlock. Because of this customized version, developer had to manually reload memcache after saving/updating a new record. As you can imagine, this code is error prone, as well as very easy the developer can forget about reloading in some cases. Indeed, that’s what happened on this case.

Let’s define de scenario:

#project.rb
has_one :manager, :foreign_key => "project_id", :dependent => :destroy

#manager.rb
belongs_to :assistant, :dependent => :destroy

Now, let’s roll up our sleeves and open a ruby console. I added some loggers in order you can see what’s going on:

project = Project.find(:last)
project.manager
project.manager.assistant
project.manager
project.manager.assistant
Mar 16 09:40:12 dhcp-client-0-104 rails[4870]: Project Load (0.000635)   SELECT * FROM `projects` ORDER BY projects.id DESC LIMIT 1
Mar 16 09:40:40 dhcp-client-0-104 rails[4870]: Manager Load (0.000579)   SELECT * FROM `managers` WHERE (`managers`.project_id = 18320478) LIMIT 1
Mar 16 09:41:34 dhcp-client-0-104 rails[4870]: [interlock] model interlock::Assistant:find:117255:default is loading from memcached

The important lines are the last two at the end. No matter how many times you ask for the manager or the assistant, in both cases same thing will happen. In the case of the manager, it will always go through database. The reason is that we are making the query by project_id and not by id. As you read at the beginning of the post, finders in interlock are just activated when you find by id. Otherwise, it goes directly through database.

In our example, project.manager.assistant goes through memcache though. Why?. Simple. In this case we are executing a find_by_id. We need to look at Assistants table for the record with id=x.

Basically depending on how you build your associations, some calls will go through memcache, and some others, directly through database.

Ger