Instalación de Ruby (la posta para mi)

En los últimos meses instalé Ruby en al menos 4 máquinas distintas (mi máquina personal, mi desktop del trabajo, una máquina virtual y mi build server). En todos los casos intenté seguir el mismo procedimiento, pero en todos me encontré con distintos issues, estimo que debido a que los ambientes eran levemente distintos (pero todos eran Ubuntu).

Cuando hablo de instalación de Ruby, no estoy hablando de la instalación base de ruby para hacer un «Hola  mundo», sino una instalación como para crear una aplicación «de verdad» (básicamente aplicación web, con conexión a internet, manejo de xml, pruebas y build automatizado).

Habiendo seteado el contexto paso a describir los pasos comunes que logré identificar en todas las instalación que realicé y que voy a seguir la próxima vez que tenga que preparar un ambiente.

Vamos a comenzar por instalar Ruby usando apt-get, no importa si luego queremos utilizar otra versión, yo me inclino por comenzar instalando ruby con apt-get pues eso se encargará de hacer varios seteos. Entonces abrimos una terminal y ejecutamos

sudo apt-get install ruby

Si no tenemos instalado Git aún, es un buen momento para instalarlo.

sudo apt-get install git

Luego vamos a instalar Ruby Version Manager (rvm). Esta herramienta nos va permitir instalar y administrar distintas versiones de Ruby en una misma máquina. Pero para instalar RVM primero tendremos que instalar git y curl, entonces:

sudo apt-get install curl
bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )
echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bashrc

Cuando finalice la instalación de estos componentes cerramos la terminal.

Ahora instalaremos ruby 1.9.2 usando RVM, para ello abrimos una nueva terminal y ejecutamos

rvm install 1.9.2

El siguiente paso es installar RubyGem, un administrador de paquetes (que en ruby se llaman gemas). La instalación de esta herramienta consisten en descargar el paquete desde http://rubygems.org/pages/download , descomprimirlo y ejecutar setup.rb (ruby setup.rb). Con esto ya estamos en condiciones de comenzar a installar gemas, pero resulta que algunas gemas en su proceso de instalación incluyen un proceso de compilación de código C, el cual puede requerir de la existencia de ciertas librerías nativas en nuestro ambiente. Por suerte las mismas pueden instalarse fácilmente utilizando apt-get.

sudo apt-get install libmysqlclient-dev libpq-dev libsqlite3-dev zlib1g-dev libreadline5-dev libssl-dev libxml2-dev libopenssl-ruby libxslt1-dev

Ahora  si, podemos proceder a la instalación de dos gemas fundamentales: rake (ruby make) y bundler (un administrador de dependencias en un punto similar a Maven).

gem install rake
gem install bundler

Con esto estamos listos para comenzar, cuando creemos nuestras aplicaciones tendremos un archivo llamado Gemfile en el cual especificaremos las dependencias de nuestra aplicación (las gemas) y con solo ejecutar bundle install, bundler se encargará de instalar las gemas especificadas.

Espero que esto les resulte útil.

Sobre el hosteo de aplicaciones en Heroku

Luego de estar trabajando con Heroku por un par de semanas, hoy voy a compartir algunos algunos consejos útiles.

Suele ser una buena práctica al desarrollar una aplicación, manejar distintos ambientes. En general suelen manejarse al menos 4 ambientes, puede que los nombres varíen, pero en líneas generales podríamos decir:

  1. Desarrollo, donde se desarrolla aplicación
  2. Test/integración, ambiente similar de desarrollo donde se ejecutan la pruebas
  3. Staging, ambiente de prueba lo más parecido posible al de producción donde se realizan las pruebas de aceptación (UAT)
  4. Producción, ambiente final donde correr la aplicación

Al trabajar con Heroku tendremos

  1. Desarrollo es la maquina del desarrollador
  2. Test/integración, es el build server
  3. Producción ya dijimos que seria heroku, por lo cual
  4. Staging también debería ser heroku.

Si uno está dispuesto a pagar, heroku nos permite manejar más de un ambiente en la misma aplicación, pero si pretendemos un enfoque gasolero al máximo, entonces tendremos que generar 2 aplicaciones: una representará nuestro ambiente productivo y la otra a nuestro ambiente de staging. Dado que el comportamiento de ciertos componentes puede varias dependiendo de ambiente en que se encuentre, para que nuestra aplicación Heroku de staging se comporte como tal, tendremos que setear la correspondiente variable de entorno utilizando el siguiente comando

heroku config:add RACK_ENV=staging

Esta variable tiene como valor por defecto production y por eso es que no la modificaremos para nuestra aplicación de producción.

Utilizando esta variable podremos definir distintos parametros de configuración para cada uno de nuestros ambientes.

configure :production do
  DataMapper::setup(:default, ENV['DATABASE_URL'])
  DataMapper.auto_upgrade!
end

configure :staging do
  DataMapper::setup(:default, ENV['DATABASE_URL'])
  DataMapper.auto_upgrade!
end

configure :development do
  DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/mydata.db")
  DataMapper::Model.raise_on_save_failure = true
  DataMapper.auto_upgrade!
end

configure :test do
  DataMapper.setup(:default, "sqlite::memory:")
end

Para poder desplegar nuestra aplicación a los correspondientes ambientes, tendremos que agregar los correspondientes repositorios git remotos. En general uno ya lo tendremos seguramente bajo el nombre heroku, pero para evitar confusiones lo mejor seria removerlo y volver a agregarlo con un nombre mas representativo. Para ello podemos hacer

git remote add production <git-de-la-app-heroku-de-production>
git remote add staging <git-de-la-app-heroku-de-staging>

El hecho de que el despligue a Heroku este basado en git, hace muy simple el versionado de la aplicación y la vuelta atras a una versión anterior. Pero más allá de esto hay un plugin que estoy utilizando llamado Releases. Este plugin ofrece cierta funcionalidad básica en su versión gratuita (como agregar un número amigable de versión a cada despliegue y la posibilidad de hacer un rollback del último despliegue).

Continuará…

Y un día llegué a Ruby…y publiqué una gema

Y si, después de haber trabajado con Delphi, PHP, C#, Java, C/C++, Smalltalk y Python finalmente me tocó Ruby.

Recién estoy dando mis primeros pasos, no conozco bien la sintáxis y al mismo tiempo hay ciertos idioms que me resultan incómodos, pero más allá de eso he encontrado varias similitudes con Smalltalk que me han resultado muy amistosas.

A diferencia de muchos de los que se acercan a Ruby, no he hechado manos a Rails. Mi stack de desarrollo se compone de Sinatra+Datamapper+SimpleDB+Heroku. He aquí otro punto interesante, luego de trabajar con la plataforma Azure, Heroku me pareció extremadamente simple y sólido. La experiencia de usuario es muy….¿suave?, en inglés diria smooth, con lo cual creo que suave es una traducción aceptable.

La aplicación que estoy desarrollando tenia como requerimiento funcionar con identidad federada. Si bien en Southwoks ya teniamos un gema para resolver dicha cuestión, la misma corria sobre Ruby 1.8 y la idea era que mi aplicación corriera sobre 1.9 pues tiene varias mejoras interesantes. Asi que luego de un poco de investigación y algunas pruebas de concepto logré dar con un código que permite federar mi aplicación usando tokens del tipo SWT.

Y estaba tan entusiasmado que di un paso más y empaqueté dicho código en un gema (este es el nombre que se le da a las librerias reutilizables en Ruby). La gema está disponible en RubyGems y el código fuente en GitHub.

Próximamente más sobre mis aventuras en Ruby.

Variables de clase y de instancia en Smalltalk

Este tema incluye algunas particularidades que me parece en general no se le presta mucha atención y por ello hoy quiero dedicarle un par de líneas.

Analicemos la definición de clase CuentaBancaria:

Object subclass: #CuentaBancaria
	instanceVariableNames: 'numero saldo'
	classVariableNames: 'SiguienteNumero'
	poolDictionaries: ''
	category: 'algo3-ejemplos'

instanceVariableNames, indica las variables de instancia, también conocidas como atributos de instancia. En Smalltalk, estas variables tienen visibilidad protegida aunque en general se las trata como si fueran privadas. En este caso tenemos las variables de instancia numero y saldo. Un detalle interesante es que las variables son protegidas de las instancia, ¿que significa esto? supongamos que tengo dos instancias de la clase CuentaBancaria: cuenta1 y cuenta2, entonces cuenta1 no puede acceder al atributo numero de la cuenta cuenta2, pues si bien cuenta2 es una instancia del mismo tiempo, resulta que otra instancia y aqui la protección es a nivel de instancias.

classVariableNames, como su nombre sugiere son variables de clase, lo cual significa que son accesibles por el objeto clase, pero al mismo tiempo también son accesibles y compartidas por todas las instancias de la clase, o sea, si una instacia modifica el valor de dicha variable, dicho cambio afecta a todas las instancias. En este caso tenemos tenemos el siguienteNumeroDisponible como variable de clase, la cual es incrementada por cada instancia cada es inicializada.

initialize
	saldo := 0.
	numero := siguienteNumero.
	siguienteNumero := siguienteNumero + 1.

Un punto importante para considerar es que esta variable también es accesible por la clase CuentaBancanria.

Por otro lado, si vamos a la definición de la clase CuentaBancaria y vemos la parte de clase, veremos.

CuentaBancaria class
	instanceVariableNames: 'MaximoNumero'

instanceVariablesNames, en este caso representa las variables exclusivas del objeto clase y como tales son accesibles por la clase, pero no por las instancias de  la clase. Un detalle interesante respecto de estas variables es donde inicializarlas. Bien, en general se suele agregar un método de clase que se encarga de inicializarlas, pero ojo este seria un método de clase.

Bien, por último, si volvemos a la definición de la clase CuentaBancaria, veremos que aún nos queda por mencionar los poolDictionaries. Estas variables son variables compartidas por instancias de distintas clases.  Es algo relativamente raro (al menos a mi parecer) y por eso es que no se ocurre como utilizarlas en el ejemplo, pero prometo escribir otro post al respecto.

Para finalizar les ofrezco un gráfico para intentar resumir el ejemplo.

(gracias Mariano por la correción)

 

 

 

Proyecto Seed (tercera parte)

En el post anterior nos habíamos quedado en: ¿que es lo mínimo que debemos poner dentro de la una imagen?

La respuesta depende de qué querramos hacer con la imagen. Básicamente podriamos decir que hay dos fines posibles:

– Cargar la imagen y trabajar creando instancias de las clases existentes, SIN agregar nuevas clases ni modificar las existentes.

– Idem caso anterior pero agregando capacidades para que la imagen pueda evolucionar incorporando nuevas clases. Para este caso es hay varias alternativas todas ellas partiendo del caso anterior y agregando por ejemplo un Compilador o algún componente capaz de cargar código binario (hay gente del equipo RMoD trabajando en esta última alternativa).

Casualmente esta mañana tuvimos una reunión en la que reorientamos nuestro enfoque y en este momento el plan es comenzar trabajando con el kernel definido por Pavel, analizarlo con algunas herramientas de análisis componentes y en base a eso identificar concretamente los cambios a realizar en cuanto a la estructura de paquetes y dependencias. El resultado de este análisis será un conjunto de backlog items para la una futura versión de Pharo (tentativamente la 1.2).

Bien, con este último post de esta serie de 3 doy por terminada la explicación de lo que intentamos hacer con el Proyecto Seed. En futuros post iré compartiendo los avances que tengamos.

Espero que se haya entendido.

Proyecto Seed (segunda parte)

Habiendo seteado algo de contexto en la primera parte ahora voy a hablar en concreto de lo que estamos haciendo en Seed. Arrancaré como bien dicen las practicas de proyectos por definir nuestra visión y misión.

Visión: Pharo cuenta con un kernel mínimo, límpio y extensible.

Misión: experimentar con distintas estrategias para crear un paquete que nos permita crear imagenes mínimas y customizables de Pharo.

Si bien esto parece bastante claro a estas alturas, las primeras 3 semanas de proyecto por momentos me sentí como turco en la neblina, pues había algunas cosas que no me cerraban. Al mismo tiempo, al comienzo nos dedicamos hacer algunas pruebas de concepto experimentado con los enfoques utilizados en otro proyectos y por momento era darse la cabeza contra la pared demasiado seguido. Por suerte, ya durante la cuarta semana de trabajo y luego de varias sesiones de peloteo con Stef y Marcus pusimos norte a nuestro barco definiendo el roadmap de trabajo.

Existen distintas posibilidades para atacar esta problemática, algunas de las cuales ya hemos descartado de entrada. Por ejemplo, hemos decidido manejar el mismo formato de imagen que Pharo, o sea, queremos seguir utilizando la misma máquina virtual (aunque no se decarta que en futuras versiones del proyecto se propongan cambios en la máquina virtual para así optimazar el funcionamiento del sistema).

Si pensamos en nuestro problema como «obtener una imagen tan chica como sea posible», básicamente existen 2 alternativas:

  1. Partir de una imagen existente y recortarla todo lo posible
  2. Partir de una imagen vacia y agregar lo mínimo necesario

Como se podrán imaginar, nosotros no somos lo primeros en atacar esta problemática, ya ha habido proyectos anteriores entre los que me parece importante destacar:

  • Chácharas: sin entrar en detalles, lo que hace es crear una imagen «vacia» y la va llenando en runtime y on the fly. O sea si cuando envia un mensaje a la clase X se intercepta la llamada, se chequea la validez del mensaje y si el mismo no se puede resolver se comunica con otro imagen e importa las clases que resulten necesarias para poder resolver la llamada. El detalle es que requiere de una máquina virtual modificada.
  • Gwen Bootstrap: este desarrollo lo hizo Gweneal Cassasio quien es también parte del equipo RMoD. Básicamente Gwen trabajó sobre Gnu-Smalltalk, modificó la máquina virtual y definió su propia imagen desde cero.
  • PharoKernel: este es un desarrollo de Pavel Krivanek quien a muy grandes rasgos tomó una imagen de Pharo y la entró a recortar y mediante prueba y error se aseguro que el subconjunto final era suficiente para cargar el sistema.

A diferencia de estos enfoques nosotros hemos decidido comenzar de una imagen vacia e ir agregando lo mínimo indispensable y al mismo tiempo de ir identificando «cosas sospechosas» para modificar en el proceso de creación de nuestra imagen.

Ahora: ¿qué es lo mínimo? Ja! ¡Que buena pregunta Mario! La respuesta queda para la próxima entrega porque no es trivial y va a requerir unas cuantas líneas.

Continuará…

Proyecto Seed (primera parte)

Finalmente después de un mes de trabajo voy a intentar explicar sintéticamente en que consiste el proyecto en el qué me encuentro trabajando. Pero dado que para entender lo que estamos intentando hacer es necesario cierto conocimiento de Smalltalk, he decidido dividir esta explicación en 2 partes. En esta primera parte voy a explicar algunas cosas básicas (o mejor dicho históricas) de Smalltalk. En la segunda parte voy a ahondar en la problemática de nuestro proyecto y en  los distintos enfoques que analizamos.

Smalltalk a diferencia de la mayoría de los lenguajes actuales, ofrece un desarrollo basado en una imagen. Esto es: al programar uno no manipula archivos de texto con código fuente, sino que el código es manipulado en el contexto de una imagen de memoria que contiene toda la definición del sistema, o sea sus clases y sus correspondientes instancias. Esta imagen es ejecutada por una máquina virtual, y en este punto sí es como Java, C# y algunos otros lenguajes actuales.

Si bien existen distintas implementaciones de Smalltalk (Gnu Smalltalk, VisualWorks, Squeak, Dolphin, Pharo, etc), todas ellas están basadas en la especificación del Blue Book, publicado a comienzo de los años ’80.

Todo sistema Smalltalk consta de dos componentes, una máquina virtual y una imagen. Una máquina virtual puede interpretar un formato específico de imagen. En el caso particular de Pharo, el formato de imagen es compatible con el formato de Squeak, porque en cierto modo Pharo surge inicialmente como un «branch» de Squeak.

La evolución de Smalltalk y en particular de Squeak/Pharo a lo largo de más de 20 años ha consistido en modificaciones «relativamente menores» en la máquina virtual y en la imagen. Y quiero que nos detengamos en algo, la imagen de Squeak se generó UNA vez, hace unos cuantos años escribiendo byte a byte según lo que esperaba la máquina virtual, de ahí en más la evolución ha consistido en modificaciones de esa primera imagen a partir de agregar/quitar/modificar clases, métodos e instancias. Si tenemos en cuenta que la imagen original data de una época en que la orientación a objetos recién daba sus primeros pasos, no es raro que al examinar el kernel de la imagen (clases Behavior, Class, Object, etc) nos encontremos con algunas cosas sospechosas desde el punto de vista de la orientación a objetos y la separación de incumbencias (dependencias poco felices, muuuuchos métodos dentro de una misma clase, métodos deprecados, etc, etc ).

Hasta aquí los conceptos, en la segunda parte entraré en cuestiones concretas del proyecto.

Clarín: así no

Estaba esta mañana como de costumbre escuchando la radio cuando escucho un comentario de la situación del Chapu y se me dio por entrar a Clarin.com a leer un poco más sobre el tema. Justamente en la home del site estaba publicado un video de la conferencia de prensa. Luego de pegar una rápida ojeada a los demás titulares decidí mirar el video. Estaba ya llegando al final del mismo (que por cierto tardó bastante en cargar) cuando repentinamente se recarga la página y el video vuelve al comienzo.

Chan!, entonces se activa mi cerebro de ingeniero:

Me parece inaceptable, es un atentado contra la usabilidad y el hecho se encuentra agravado porque estamos hablando de uno de los portales de contenido más importante del país. Si esto ocurría hace 4 años, podría pasarse por alto, pero no hoy en día con el auge de la Web 2.0, las tecnologías AJAX y el surgimiento de los nuevos estándares HTML.

Ya mismo, curso de usabilidad y Web 2.0 para los programadores de Clarin.

Say no more.

Hola 2010, hola Linux

Un nuevo año comienza y por quinta vez voy a intentar usar linux como sistema operativo de cabecera (ya en algún otro momento contaré sobre mis 4 experiencias previas). En realidad esta experiencia comenzó durante diciembre de 2009, cuando instalé en mi Dell XPS Studio un Ubuntu 9.04 particularmente tuneado que descargué del sitio de Dell. Primero corrí el Live CD para ver si los principales dispositivos era reconocidos y por suerte todo levanto perfectamente a excepción del audio. Después de algunas pruebas básicas decidí instalarlo en modo dual boot con el Windows7 que ya tenía instalado. Una vez instalado, al intentar reproducir audio por primera vez el propio Ubuntu se encargó de encontrar un driver apropiado y previa validación conmigo se encargó de instalarlo y chan! tuve sonido. A continuación me encargué de instalar algunos herramientas de desarrollo como Java, Eclipse, MySql, Pharo y Ruby. Luego instalé algunos programa de uso general como aMsn, VLC, VirtualBox y Thunderbird. Hasta aquí todo fue feliz, realmente el comando apt-get provee una experiencia de usuario muy cómoda. La cosa dejo de ser tan feliz cuando intenté configurar el modem USB de banda ancha móvil. Tuve que googlear un rato y luego de probar varias instrucciones de distintas fuentes, logré que Ubuntu lo reconociera, pero para entonces ya había invertido más de 5 horas. En un futuro post voy a detallar el procedimiento que seguí para hacer funcionar el modem. Por ahora, solo me resta decir que en este momento estoy escribiendo este post felizmente desde Ubuntu.

After three months on windows7

It still seems much more stable than Vista (and it is a release candidate version!). I have successfully tested some other programs:

  • CorelDraw14
  • Google Chrome
  • RapidSVN
  • Eclipse
  • Jude UML
  • Paint.Net
  • Skype

Unfortunately Sony Wireless Manager stopped working, to be precise, the problem is that it does not recognize the modem. I still have the problem with Winamp and my touchpad, but I am happy despite of that.