Gastón Ramos

"La mayoría de las gaviotas no se molesta en aprender sino las normas de vuelo más elementales: como ir y volver entre playa y comida. Para la mayoría de las gaviotas, no es volar lo que importa, sino comer. Para esta gaviota, sin embargo, no era comer lo que le importaba, sino volar. Más que nada en el mundo, Juan Salvador Gaviota amaba volar".

Tag: ruby

Como instalar passenger con nginx en menos de 15 minutos

Hace un tiempo estuve trabajando desde el laboratorio de altoros, en crear un tutorial para instalar passenger con nginx, para esto desarrolle un pequeño script con instrucciones y grabe un screencast, si vos queres ver como se instala passenger y nginx en menos de 15 minutos acá te dejo el screencast y el link al repo con las instrucciones y los scripts:

https://github.com/gramos/ruby-passenger-tutorial

 

Advertisements

Rubylit meetup marzo 2015

Ayer jueves como a las 20hs en las oficinas de Altoros hicimos la primer meetup del año 2015 del grupo de Rubystas de Santa Fe y alrededores, asistieron al evento: @jjconti, @olvap, @ArmandoAndini, @eloyesp, @rmgarciap, @srmanuq, @alener014 , @juanfgs, @gsgerman, @marielcior, @hpmaxi, @gastonramos.

Había dos charlas programadas, la primera fué “Bad Practices driven development” que la dí yo, la verdad la charla no la preparé tanto, sin embargo me quedé conforme, algunos de los temas de los que hablé: “A veces programo antes de pensar, empiezo escribiendo código y después voy madurando la idea de lo que quiero”, “Rails DB ConnectionPool”, “Threads”, “Fork” y procesar cosas en background en general, los slides de la charla los pueden ver acá, que no tienen mucho sentido por sí solos. Además de mi charla @alener014 titulada “Como me hubiera convencido a mi mismo de pasarme a ruby: algunas fantasias y ciertas realidades” que la  pueden ver acá, la idea era que Alejandro (el orador) viajaba al pasado para convencerse a sí mismo de qué tenía que aprender ruby en vez de python, los slides ivan pasando y los argumentos eran debatidos entre Alejandro y le resto de los asistentes, “Cucumber vs Letucce”, “Debug, preguntarle cosas a la aplicación”, “monads” son algunos ejemplos de la excelente charla final, luego de disfrutar de unas excelentes pizzas de provenzal, muzzarella y napolitana y de que Juanjo nos cuente como es su nuevo desafío aprendiendo “Swift”.

 

 

Es ruby el java del momento?

ruby-javaNunca me voy a olvidar cuando empecé a programar con Ruby, todo era nuevo y casi todo era un desafío, no había tanta documentación y las cosas eran bastante artesanales, no existía bundler ni RVM ni Rbenv, sin embargo las cosas se hacían igual :). Me acuerdo bien que me gustaba mucho Ruby on Rails y no sé si ahora diría lo mismo, me gustaba tanto que hasta daba charlas de evangelización y en uno de los slides mostraba una imágen comparando la cantidad de libros que tenías que leer para aprender Java y la cantidad para aprender ruby, la imágen era esta:

Java vs Ruby

Además me acuerdo que las veces que hice algunas cositas con Java no me gustaba la complejidad que llevaba hacer cosas simples, para todo había que crear clases, todo era complejo.
Pasaron ya casi 9 años desde empecé a escribir mis primeras líneas de código en Ruby, he pasado por muchos proyectos, algunos desde cero y otros legacy, aplicaciones más grandes, más chicas, etc, mi forma de programar ha pasado por varios estadíos, desde el 2004 cuando conocí Test Driven Development y me hice fanático, cuando no escribía casi nada sin escribir un test, y cuando me peleaba con todo el mundo para que escriba tests o para que corra los tests antes de pushear :). Hoy con mucha más experiencia encima, me doy cuenta que Ruby se parece mucho a java en algunas cosas y eso no me gusta, las aplicaciones son cada vez más complejas, se ha perdido “lo artesanal”, cada aplicación de Rails en la que he trabajado tiene como promedio 5000 Líneas de código sin contar las dependencias y otras 10000 líneas para los tests, el 90% de la gente escribe sus aplicaciones usando Ruby on Rails agregando gemas para cada cosa que necesita sin pensar en el costo extra que eso conlleva, el 90% usa Rspec sin si quiera darse la posibilidad a la duda y muy pocos tienen tests bien escritos de manera que al modificar algunas pocas líneas no se rompan 50 tests.
Y como si esto fuera poco, existen cada vez más cosas algunas menos necesaria que otras así que si alguien quiere empezar a programar en una app existente en ruby, cuales son las cosas que debería aprender?

[ Ruby ]
[ Rake ]
[ RVM / Rbenv ]
[ Rails ]
[ Rubygems ]
[ Rspec ]
[ Sidekiq / Rescue ]
[ Capybara ]
[ Cucumber ]

Ruby books
Y la lista tranquilamente podría seguir.

Pero volviendo al tema de “lo artesanal” siento como que ya está todo “programado” y pensado, si hay que hacer una página web entonces tenemos que usar Ruby on Rails, para escribir los tests hay que usar Rspec aunque si sos un poco revolucionario vas a usar minitest, hay alguna acción que lleve mucho tiempo? entonces seguro que tenemos que usar Sidekiq o Rescue. Del lado del servidor existe muy poca gente que se ponga a armar una infraestructura de producción para una app chica, la mayoría usa Heroku o cosas similares.

Otro tema interesante es la forma de trabajo del día a día, dónde parece ser que la única manera de llevar adelante un proyecto de software es utilizando Scrum con daily meetings…ufff “Qué hiciste ayer?”, “Qué vas a hacer hoy?” participé en algunos proyectos donde sufrí la peor variante de Scrum, dónde los sprints duraban una semana y teníamos en algunos casos más de 10 reuniones por sprint, “IPM”, “Post Mortem”, “Retro” son algunos de los nombres de estas reuniones, pero bueno voy a cambiar de tema por que me empieza a doler la cabeza…

Podría por ejemplo hablar de feature-branch, pero a lo mejor ese es tema para otro post otro día.

Panthro, el proxy cache para rubygems.

Hace un tiempo atrás se me ocurrió escribir un proxy cache para las gemas, lo hice un poco para aprender y otro poco a para acelerar un poco el uso del rubygems en un lugar común de trabajo, como por ejemplo una oficina. La idea es que cuando instalamos un gema por primera vez esta se baja desde rubygems y se guarda en el cache en dónde panthro está corriendo, específicamente en ~/.panthro/gems, luego cuando necesitemos instalar la misma gema desde otra máquina en la misma red y que tenga configurado panthro como source de rubygems (veáse el comando `gem source`) esta y todas sus dependecias no necesitan ser descargadas dado que ya están en el cache.

Panthro

Hay algunas cosas que me falta implementar y es expirar es el cache de los archivos latest_specs.4.8.gz, prerelease_specs.4.8.gz y specs.4.8.gz entre otras que están detalladas en el TODO del proyecto.

https://github.com/gramos/panthro

Es bueno aclarar que hasta ahora panthro tiene 63 líneas de código sin contar los tests. Además para poder testear que tan rápido es Panthro y compararlo contra usar directamente rubygems hice una gema muy chiquita que se llama rumb y que podés mirar acá: https://github.com/gramos/rumb esta tiene 57 líneas de código contando el texto del ayuda.

Desinstalando rbenv de ruby

Desde hace algunos días que estoy haciendo unas pruebas con algunas gemas, hoy instalé geminabox y cuando quiero probarlo como dice en el README, obtengo un LoadError: ‘geminabox’ not found, a lo cual pensé not found? pero si lo acabo de instalar…
Después de revisar un poco, ejecuto `gem env` y veo que tengo un quilombo con los GEM_PATH y GEM_HOME dado que tengo instalado rbenv ( https://github.com/sstephenson/rbenv ) para manejar las versiones de ruby y además de rbenv tambien tengo el plugin communal ( https://github.com/tpope/rbenv-communal-gems ) para compartir las gemas entre las versiones compatibles de ruby.
Además tengo instalado el paquete rybgems-integration que también hace cosas con rubygems, o sea un kilombo. Después de hacer varias pruebas y ver que las cosas no funcionan muy bien, decidí desinstalar rbenv por ahora y me encontré con no hay un `rbenv uninstall` Así que esta es la receta para hacerlo:

Borro todo el contenido del directorio rbenv:

rm -rf ~/.rbenv

Elimino todo lo agregado en los archivos del shell:

grep rbenv ~/.bashrc ~/.bash_profile ~/.zshrc /etc/profile /etc/profile.d/*

Luego de esto hago un `gem env` y veo que todavía sigo teniendo los path the rbenv:

Econtré que tenía un GEM_HOME agregado en el archivo de conf de rubygems y me decidí a borrar este archivo:

rm ~/.gemrc

después de esto tengo un máquina en un ambiente de rubgems más o menos “limpio”, más adelante instalaré rbenv de nuevo.

Bless.

La mejor meetup de Rubylit del año

Ayer miércoles como a las 8:30 de la noche y después de estar dando vueltas durante 30 minutos para encontrar lugar para estacionar, llegué a la oficina de Altoros dónde una vez por mes hacemos la meetup de Rubylit, esperaba encontrarme con 4 o 5 personas que eran las que venían confirmando en la lista de mails #rubylit, pero para mi sorpresa había como 15. Las charlas programadas era 2, la de mi amigo Humitos “Como matar el sueño de todo programador en 2 minutos” dónde cuenta más o menos como fueron las experiencias vividas en su proyecto “Argentina en Python” http://elblogdehumitos.com.ar/pages/argentina-en-python/ y dónde lo único que tengo que agregar es que el título de la charla de es un poco engañoso por que fueron más de 2 minutos :), y la otra charla era la de David Capello desarrollador principial de http://www.aseprite.org/, nos contó como está logrando vivir de lo que más le gusta hacer que es desarrollar este editor de animaciones para video juegos llamado aseprite, que la verdad que me encantó, tiene una interfáz muy Retro que creo que no debería cambiar nunca, a pesar de lo que él piensa :).
Una parte de la meetup que me gustó mucho fué más o menos en el medio de la charla de Humitos dónde no todos empezaron a hablar, no sólamente el orador y salieron temas muy interesantes que tienen que ver con las motivaciones, el conocimiento, como poder hacer lo que nos gusta, aprendizaje constante, diversión, supervivencia, etc.

Aviso: Voy a subir las fotos pronto.

Acá están las fotos, hacer click en la foto:
DSC_1780_01

Herramientas del día a día

Durante mi jornada de trabajo de programador, uso varias herramientas, algunas las uso desde hace mucho otras no tanto, por ejemplo, para abrir y editar archivos uso emacs, que todavía no lo sé manejar como quisiera, pero es altamente poderoso.
Otra cosa que uso es screen para multiplexar sesiones de bash en una misma terminal.
Además de estas dos cosas uso mucho git, y en particular estoy aprendiendo a usar Magit que es un modo de emacs para git.
Acá dejo unos links útiles más que nada para tenerlos para mí, todos en un sólo lugar.

Emacs card reference:

http://www.gnu.org/software/emacs/refcards/pdf/refcard.pdf

Screen:

http://aperiodic.net/screen/quick_reference

Magit:

http://magit.github.io/documentation.html

Guard:

https://github.com/guard/guard

Deploying Cloud Foundry with bosh-lite

This is my tutorial of how to deploy cloud foundry using bosh-lite, as you may know there is a tutorial in the bosh-lite Readme file but there are some tiny step that the tutorial does not cover and I always forget and that is the reason why I’m writing my own.

git clone git@github.com:cloudfoundry/bosh-lite.git
cd bosh-lite
vagrant plugin install vagrant-omnibus
bundle
librarian-chef install
vagrant up
bosh target 192.168.50.4
./scripts/add-route

wget http://bosh-jenkins-gems-warden.s3.amazonaws.com/stemcells/latest-bosh-stemcell-warden.tgz
bosh upload stemcell latest-bosh-stemcell-warden.tgz

All the previous steps are explained in the bosh-lite tutorial. You can see the original tutorial here: https://github.com/cloudfoundry/bosh-lite

Now we are going to clone the cf-release repo that is a bosh release for cloudfoundry;

cd ..
git clone git@github.com:cloudfoundry/cf-release.git

and now we need to point our the release dir for bosh:

export CF_RELEASE_DIR=~/cloudfoundry/cf-release/

Now we can upload the latest cloud foundry release which at this moment is 145:

bosh upload release ../cf-release/releases/cf-145.yml

Uploading release
release.tgz:   100% |oooooooooooooooooooooooooooooooooooooo|   1.1GB  53.3MB/s Time: 00:00:21
HTTP 500: 

Oooops :( I got an error, I’m trying to find where the bosh packages are stored, doing little bit of research
I found that bosh-lite use https://github.com/cloudfoundry/bosh/blob/master/simple_blobstore_server
simple_blobstore_server is a sinatra API that store.

Finally I restarted the Vm tried again and just worked:

bosh releases

------+----------+-------------+
| Name | Versions | Commit Hash |
+------+----------+-------------+
| cf   | 145      | 41733e43+   |
+------+----------+-------------+
(+) Uncommitted changes

Releases total: 1

So, we uploaded our bosh release cloud foundry, now we need a deploy manifest:

./scripts/make_manifest

bosh status

Config
             /home/gramos/.bosh_config

Director
  Name       Bosh Lite Director
  URL        https://192.168.50.4:25555
  Version    1.5.0.pre.1117 (3300587c)
  User       admin
  UUID       365eb26d-146e-4d12-888f-d9249dbef375
  CPI        warden
  dns        enabled (domain_name: bosh)
  compiled_package_cache enabled (provider: local)
  snapshots  disabled

Deployment
  Manifest   ~/cloudfoundry/bosh-lite/manifests/cf-manifest.yml

and run the deploy:

bosh deploy

You can see the vms created by bosh to check that the deploy worked:

Deployment `cf-warden'

Director task 228

Task 228 done

+------------------------------------+---------+---------------+--------------+
| Job/index                          | State   | Resource Pool | IPs          |
+------------------------------------+---------+---------------+--------------+
| cloud_controller/0                 | running | common        | 10.244.0.14  |
| dea_next/0                         | running | dea           | 10.244.0.126 |
| health_manager/0                   | running | common        | 10.244.0.122 |
| loggregator-trafficcontroller_z1/0 | running | common        | 10.244.0.82  |
| loggregator-trafficcontroller_z2/0 | running | common        | 10.244.0.86  |
| loggregator_z1/0                   | running | common        | 10.244.0.74  |
| loggregator_z2/0                   | running | common        | 10.244.0.78  |
| login/0                            | running | common        | 10.244.0.118 |
| nats/0                             | running | common        | 10.244.0.6   |
| postgres/0                         | running | common        | 10.244.0.250 |
| router/0                           | running | router        | 10.244.0.254 |
| syslog_aggregator/0                | running | common        | 10.244.0.2   |
| uaa/0                              | running | common        | 10.244.0.10  |
+------------------------------------+---------+---------------+--------------+

VMs total: 13

and that’s all!

If you want to review some bosh concepts here are some documentation:

http://docs.cloudfoundry.com/docs/running/bosh/reference/

Como usar COPY from con ruby y PG driver

Estoy trabajando en un proyecto dónde necesito importar unos archivos csv muy grandes, apróximadamenteunos 40 millones de registros cada uno, luego de varias pruebas con ruby, decidí usar COPY from, sencillamente por que el script de ruby demorarba unas 15hs mientras que el copy from 20 minutos, pasé por varios errores intentando correr el COPY from con Sequel uno de los errores decía que para correr COPY from file debo ser super usuario, y que podía usarCOPY from STDIN como usuario normal (error de PG) así que la forma que encontré de correr el copy from STDIN es usando directamente el driver de PG así:

class CopyCsvImporter

  def initialize(csv_file, args)
    @csv_file     = csv_file
    @separator    = args[:separator]
    @delete_table = args[:delete_table]
    @fields       = args[:fields]
    @table        = args[:table]
  end

  def copy_cmd
    "COPY #{@table} (#{@fields}) FROM STDIN DELIMITER '|'"
  end

  def conn
    conn_args = {:dbname => App.db_conf['database'], :user => App.db_conf['username'],
                 :password => App.db_conf['password'], :host => App.db_conf['host']}

    @conn ||= PG.connect conn_args
  end

  def import!
    conn.exec copy_cmd
    File.open(@csv_file) do|f|
      f.each_line{|line| conn.put_copy_data(line)}
    end
    conn.put_copy_end
  end

end

Preste atención sobre todo al método import. Esto fué todo!

¿Cuales son las diferencias entre el GC de php y el de ruby ? Parte II

Syntactic y semantic garbage

El alcance de la definición de “basura” no es óptimo, por lo que las última
vez que un programa usa un objeto podría ser mucho antes de que este
caiga fuera del ámbito del ambiente.Una distinción es a veces delineadaentre “syntactic garbage”, aquellos objetos que el programa no tiene la posibiladad de acceder, y “semantic garbage”, aquellos objetos que de hecho el programa no usará jamás.

x = Foo.new
y = Bar.new
x = Quux.new

# en este punto, sabemos que el objeto Foo
# originalmente asignado a x no será accedido nunca
# esto es “syntactic garbage”

if x.check_something
   x.do_something y
end

exit 0

# en el código de arriba “y” *podría* ser “semantic garbage”
# pero no lo vamos a saber hasta que c.check_something retorne
# algún valor — si es que retorna alguno.


Referencias fuertes y débiles.

El GC puede reclamar solamente objetos que no tienen referencias apuntando hacia ellos tanto sea directa o indirectamente desde el conjunto raíz (root set). Por otro lado
algunos programas requieren referencias débiles, las cuales deberían ser útiles
tanto tiempo como el objeto exista pero no deberían prolongar su tiempo de vida.
En discusiones acerca de referencias débiles las referencias ordinarias son a veces llamadas referencias fuertes. Un objeto es apto para ser recolectado por el GC si no hay referencias fuertes hacia este, aún pudiendo haber alguna referencia débil.

Una referencia débil no es simplemente cualquier puntero al objeto la cual al GC
no le importa. El término es usualmente reservado para una categoria apropiadamente manejada de referencia especial a objetos los cuales son seguros de usar aún después de que el objeto desaparece porque apuntan a un valor seguro. Una referencia insegura que no es conocida por el GC simplemente va a continuar colgada  y continuamente referenciando a la dirección dónde el objeto previamente residía. Esto no es una referencia débil.

En algunas implementaciones, las referencias débiles están dividas en subcategorías, Por ejemplo, la máquina virtual de java provee tres formas de referencias débiles, llamadas soft references [3], referencias fantasmas [4] y referencias débiles normales [5], Un objeto referenciado suavemente es únicamente apto para su reclamo, si el GC decide que el programa está bajo en memoria. Distinto a las referencias suaves o las  referencias débiles normales, una referencia fantasma no provee acceso al objeto que esta referencia. En cambio, una referencia fantasma es un mecanismo que permite al GC notificar al programa cuando el objeto referenciado se convierte en una referencia fantasma.

[3] http://docs.oracle.com/javase/7/docs/api/java/lang/ref/SoftReference.html
[4] http://docs.oracle.com/javase/7/docs/api/java/lang/ref/PhantomReference.html
[5] http://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html

Continuará….