Thursday, January 24, 2013

Rails: Configuración del entorno específico


En este post quiero comentar un plugin interesante para la configuración de un entorno específico en un proyecto Rails.

Se añade al GemFile la siguiente línea: gem "rails_config". RailsConfig ayuda a administrar la configuración del entorno específico. Lo único que tenemos que hacer es bundle install. Una vez que hagamos esto ejecutamos la siguiente instrucción: rails g rails_config:install

 En nuestra aplicación vamos a tener las siguientes carpetas:
config/settings.yml
config/settings/development.yml
config/settings/production.yml
config/settings/test.yml


Es decir vamos a tener un archivo YAML por cada uno de los entornos de nuestra aplicación y un archivo común para todos los entornos que es el settings.yml; es decir será visible por todos los entornos. Dependiendo del entorno en el que tengamos levantada la aplicación leerá de un fichero u otro.

La instrucción que ejecutamos antes creará un archivo en config/initializers, rails_config.rb, donde se define el nombre de la constante a través de la cual vamos a acceder a los parámetros definidos para cada entorno. Por defecto se llama Settings. Esta constante se puede cambiar por la que consideremos oportuna.



Ejemplo

Imaginemos que tenemos definido lo siguiente en cualquiera de los archivos mencionados:

size: 2
section:
  size: <%= 1 + 2 + 3 %>
  servers: [ {name: yahoo.com}, {name: amazon.com} ]
 
Para poder acceder a estas variables desde cualquier parte de nuestra aplicación haríamos lo siguiente:

Settings.size   # => 2
Settings.server # => google.com
Settings.section.size # => 6
Settings.section.servers[0].name # => yahoo.com
Settings.section.servers[1].name # => amazon.com

Monday, January 21, 2013

proc y lambda en Ruby


En este post vamos a hablar de como su usan los procs y lambdas en Ruby así como las diferencias que existen entre ambos.


La primera diferencia que existe entre ambos es en el paso de parámetros.

         ruby-1.9.3-p125 :003 > p = proc{|x, y| puts x+y}
         => #<Proc:0x000000067de2a8@(irb):3>

         ruby-1.9.3-p125 :004 > p.call 1,2
         3
         => nil

         ruby-1.9.3-p125 :006 > p.call 1,4,"prueba"
         5
         => nil

        ruby-1.9.3-p125 :007 > l = lambda{|x, y| puts x+y}
        => #<Proc:0x000000068f1d20@(irb):7 (lambda)>

        ruby-1.9.3-p125 :010 > l.call 1,2
        3
        => nil

        ruby-1.9.3-p125 :011 > l.call 1,2, "prueba"
        ArgumentError: wrong number of arguments (3 for 2)
        ...

Como podemos ver proc ignora los demás parámetros que le pasamos a mayores, sin embargo lambda da un error.


 Comportamiento con el método return:                                                                                                
        ruby-1.9.3-p125 :018 > l = lambda do
        ruby-1.9.3-p125 :019 >     1 +2
        ruby-1.9.3-p125 :020?>   return "funciona"
        ruby-1.9.3-p125 :021?>   3 + 4
        ruby-1.9.3-p125 :022?>   end
        => #<Proc:0x00000006940498@(irb):18 (lambda)>
        ruby-1.9.3-p125 :023 > l.call
        => "funciona"
 
        ruby-1.9.3-p125 :024 > p = proc do
        ruby-1.9.3-p125 :025 >     1 +2
        ruby-1.9.3-p125 :026?>   return "funciona"
        ruby-1.9.3-p125 :027?>   3 + 4
        ruby-1.9.3-p125 :028?>   end
        => #<Proc:0x00000005976030@(irb):24>
        ruby-1.9.3-p125 :029 > p.call
        LocalJumpError: unexpected return


        ruby-1.9.3-p125 :030 > def ejemplo_proc
        ruby-1.9.3-p125 :031?>   p = Proc.new { return "asi me permite hacer return"}
        ruby-1.9.3-p125 :032?>   p "tambien lo veo"
        ruby-1.9.3-p125 :033?>   p.call
        ruby-1.9.3-p125 :034?>   p "esto ya no lo puedo ver"
        ruby-1.9.3-p125 :035?>   end
        => nil
        ruby-1.9.3-p125 :036 > ejemplo_proc
       "tambien lo veo"
        => "asi me permite hacer return"

        ruby-1.9.3-p125 :037 > def ejemplo_lambda
        ruby-1.9.3-p125 :038?>   p = lambda { return "asi me permite hacer return"}
        ruby-1.9.3-p125 :039?>   p "tambien lo veo"
        ruby-1.9.3-p125 :040?>   p.call
        ruby-1.9.3-p125 :041?>   p "esto ya no lo puedo ver"
        ruby-1.9.3-p125 :042?>   end
        => nil
       ruby-1.9.3-p125 :043 > ejemplo_lambda
       "tambien lo veo"
       "esto ya no lo puedo ver"
       => "esto ya no lo puedo ver"

Saturday, January 19, 2013

DRY: Metaprogramación


Ruby es un lenguaje dinámico y precisamente la metaprogramación digamos que no es más que escribir programas que escriben programas. De ahí el nace el concepto de DRY ó "no te repitas a ti mismo". Veamos esto con un ejemplo sencillo:

Imaginemos que tenemos un Tweet que puede tener 3 estados: pendiente, publicado y censurado.
En un primer momento se nos puede ocurrir definir 3 constantes para la clase Tweet que identifiquen cada uno de los estados anteriores:

class Tweet < ActiveRecord::Base

   PENDING = 0

   PUBLISHED = 1

   CENSURED = 2

end 


Ahora se nos podría ocurrir ir definiendo todos aquellos métodos de clase que necesitaríamos para extraer de base de datos todos los tweets en estado de pendientes, publicados o censurados. O incluso métodos de instancia para saber el estado de un tweet en concreto. Algo de esta manera:

class Tweet < ActiveRecord::Base

   PENDING = 0

   PUBLISHED = 1

   CENSURED = 2

   def self.all_pending
     find(:all, :conditions => { :status => PENDING }
   end

  def self.all_published
    find(:all, :conditions => { :status => PUBLISHED }
  end

  def self.all_censured
    find(:all, :conditions => { :status => CENSURED }
  end

  def pending?
    self.status == PENDING  
  end

  def published?
    self.status == PUBLISHED  
  end

  def censured?
    self.status == CENSURED  
  end

end

Sin embargo se puede hacer mejor, más DRY, y con menos posibilidad de errores usando métodos dinámicos. Veamos el código para entenderlo de manera rápida y sencilla:

class Tweet < ActiveRecord::Base 
    STATUSES = { 
        :pending => 0, 
        :published => 1, 
        :censured => 2 
    } 
    STATUSES.each do |status, value| 
        define_method :"#{status}?" do 
            self.status == value 
        end 
        define_method :"#{status}!" do 
            self.status = value 
        end 
    end 
    class <<self
      STATUSES.each do |status_name|
         define_method "all_#{status_name}" do
           find(:all, :conditions => { :status => status_name }
         end
      end
    end
end

Como se puede ver no repetimos tanto código que es lo que nos hace ser más DRY. Definimos el conjunto de estados como una Hash para poder recorrer ese conjunto y usamos define_method que nos da más flexibilidad que def ya que nos permite pasarle un parámetro, en este caso el estado, e ir definiendo de manera dinámica los distintos métodos que comentábamos anteriormente.

Wednesday, January 16, 2013

Behavior-Driven Development (BDD): Cucumber

Desarrollo guiado por comportamiento, o Behavior Driven Development (BDD) es una técnica de Desarrollo Agil de Software que fomenta la colaboración entre desarrolladores, testers, analistas y personas del negocio en un proyecto de software. Crea un entendimiento común de todos los involucrados y ayuda a eliminar malos entendidos sobre lo que el sistema debe hacer.

Frameworks de BDD

 Las herramientas de BDD se centran en describir el comportamiento de un software de una manera muy comprensible para todos los involucrados. En este post vamos a describir la herramienta Cucumber

Cucumber

Cucumber es una herramienta que permite ejecutar tests a partir de una descripción funcional en texto plano.
El poder de Cucumber radica en la facilidad de describir un comportamiento determinado. Esta descripción se realiza en Gherkin, un Business Readable DSL que permite que cualquier persona defina reglas sin necesidad de contar con conocimientos de programación.

Estos tests brindan la posibilidad de ser verificados por analistas y personas no técnicas que quizás sean expertos en el dominio de la aplicación.

Features

Una feature es algo que el software hace o debería hacer. La estructura general de una feature es la siguiente:

Feature: <short description>
<story>
<scenario 1>
...
<scenario n>

El formato común para el <story> es:

As a <role>
I want <feature>
so that <business value>

que responde a tres cuestiones importantes: 
  1. ¿Quién está usando el sistema?
  2. ¿Qué están haciendo?
  3. ¿Por qué les importa?

Scenarios

Una feature es definida por uno o más escenarios. Un escenario es una secuencia de pasos.
Un escenario se compone de tres secciones relacionadas con los 3 tipos de medidas:

1. Given: Esto crea condiciones previas, o el contexto para el escenario.
2. When: Comportamiento que se está enfocando.
3. Then: Postcondiciones ... comprueba que se hace lo correcto en el comportamiento que se está enfocando en el paso 2.

La forma general de un escenario es la siguiente:

Scenario: <description>
<step 1>

<step n>


Proceso de instalación y ejemplo de ejecución

        En el GEMFILE añadir:

group :test do

    gem 'cucumber-rails'
    gem 'capybara'
    gem 'database_cleaner'

end

  • Ejecutar bundle install en una consola.
  • Ejecutar rails generate cucumber:install (genera las carpetas necesarias, entre ellas la de features)

La estructura que toma dentro del proyecto es la siguiente:

features:

step_definitions

    web_steps.rb

support

    env.rb (configuration file cucumber)

    paths.rb (Maps a name to a path)

        rails generate cucumber:feature “nombre de la feature” (rails generate cucumber:feature “Article”)

Creara los archivos: manage_articles.feature donde se definen los posibles escenarios y article_steps.rb donde se definen los pasos intermedios:

features:
→ step_definitions

    web_steps.rb

    article_steps.rb

→ support

    env.rb (configuration file cucumber)

    paths.rb (Maps a name to a path)

→ manage_articles.feature

Ejemplo

Definimos en manage_articles.feature un escenario de la forma:

Feature: Manage articles

In order to make a blog

As an author

wants to create and manage articles

Scenario: Articles List

Given I have articles titled Pizza, Breadsticks

When I go to the list of articles

Then I should see "Pizza"

And I should see "Breadsticks"

Se procede a definir los “steps” relevantes (cada step se va a corresponder con cada una de las líneas identificadas para el escenario definido), que atienden a expresiones regulares :

En article_steps.rb:

Given /^I have articles titled (.+)$/ do |titles|

titles.split(', ').each do |title|

Article.create!(:title => title)

end

end

En web_steps.rb está definido el step para la segunda línea del escenario

“When I go to the list of articles”:

When /^(?:|I )go to (.+)$/ do |page_name|

visit path_to(page_name)

end




        cucumber features

Using the default profile...

....

1 scenario (1 passed)

4 steps (4 passed)

0m0.529s

Tuesday, January 15, 2013

Resque Hooks y Scheduler


Existen diferentes tecnologías que se pueden utilizar para programar jobs en segundo plano: entre ellas utilizando un almacén de datos NoSQL como Redis y Resque para su gestión.

En este artículo me gustaría hablar sobre los hooks y sobre resque-scheduler. Los hooks sirven para añadir comportamiento adicional a un plugin, en este caso al tratamiento y ejecución de un job y el segundo 'resque-scheduler' es una extensión para Resque que añade soporte para tratar jobs en un futuro. Veámos ambos conceptos con un poco más de tranquilidad y con ejemplos sencillos. Yo creo que ambos conceptos van un poco de la mano:

Job Hooks

Estos son algunos de los hooks que hay disponibles:


  • before_enqueue
  • after_enqueue
  • before_perform
  • after_perform
  • on_failure_retry  
  • etc

Veamos por ejemplo el funcionamiento del hook on_failure_retry, un hook interesante ya que va añadir un compartimiento  adicional en el caso de que el job que ejecutemos falle.

Imaginemos que tenemos un job que lo que hace es enviar emails en segundo plano a los usuarios de una aplicación:




require 'resque'
class EnvioEmailsJob < Jobs::Base
   def self.perform(opts = {})
      mail = UsuariosMailer.email_users(opts) # => a Mail::Message object
      mail.deliver   # sends the email
   end
end


Ahora vamos a añadir un hook y darle el comportamiento deseado en el caso de que el job que procesa el email fallara. Este es un punto interesante porque en determinadas aplicaciones podría ser un punto crítico y necesario para el correcto funcionamiento de la misma.
A continuación defino como sería el código para añadir el hook y su funcionalidad, en este caso vamos a modificar su comportamiento a través del plugin resque-scheduler, que entre otras cosas tiene una función que nos permite reencolar el job que ha fallado y decirle cuando queremos que se ejecute, porque de otro modo se ejecutaría de manera recursiva y no queremos que suceda eso:


module Jobs
  # Callbacks in jobs execution.
  # Esta clase debe ser la superclase de cualquier trabajo para controlar su      ejecución.
  
  class Base
      def self.on_failure_retry(e, *args)     
         next_execution = time_now.change(:min => 50)
         # función de resque-scheduler para reencolar el job y se ejecute en un    momento determinado, en este caso cada 50 minutos.
         Resque.enqueue_at(next_execution, self, *args)
      end 
  end
end

Scheduled Jobs

Son tareas programadas, como vimos en el ejemplo anterior la sintaxis es de la forma:

Resque.enqueue_in(5.days, SendFollowupEmail) # ejecutar un job en 5 días
# ó
Resque.enqueue_at(5.days.from_now, SomeJob) #  ejecutar un job a una hora especifica.

 




Sunday, January 13, 2013

Apache Thrift


Es un framework JAVA para el desarrollo de servicios escalables multi lenguaje. Esto permite crear servicios que trabajan eficiente y transparentemente entre los lenguajes de programación más populares (C++, Java, C#,Python, Ruby, PHP entre muchos otros).
Apache Thrift permite a los desarrolladores definir los tipos de datos e interfaces de servicios en un archivo único en lenguaje neutral y generar todo el código necesario para construir clientes RPC y servidores.

 Primeros pasos con Apache Thrift

  1. Descarga Apache Thrift
  2. Instalación
  3. Ahora ya puedes empezar a escribir tu primer archivo thrift. Para generar el código en el lenguaje que más os convenga o interese sólo teneis que ejecutar la siguiente instrucción:
thrift --gen <lenguaje de programación> <nombre del fichero Thrift>





 Ejemplo de Apache Thrift con Ruby

Vamos a definir una estructura sencilla de un objeto User con tipos de datos básicos, donde el sexo del usuario va ser un tipo de dato enumerado:

enum SexType {
  MALE = 1,
  FEMALE = 2
}

struct User {
  1: string firstname,
  2: string lastname,
  3: i32 user_id = 0,
  4: SexType sex,
  5: bool active = false,
  6: optional string description
}


Guardamos el archivo como user.thrift por ejemplo.
Si queremos generar el código ruby asociado al archivo .thrift que acabamos de especificar ejecutaríamos la siguiente instrucción:
thrift --gen rb user.thrift