sábado, 28 de noviembre de 2009

Conferencia Rails 2009 - Impresiones

Por tercer año he asistido a la conferencia rails y este año he salido con la sensación de que la conferencia ya se ha consolidado y se ha hecho mayor.

Los años anteriores se hablaba de como trabajar con rails, plugins y herramientas que facilitan el trabajo, bastante sobre buenas prácticas de programación y escalabilidad y muchísimo de BDD, TDD y cualquier cosa relacionada con testing.

Pero este año ha sido diferente. Ha habido mucha filosofía sobre como trabajar en magníficas conferencias como la de javi (La herramienta de desarrollo definitiva) y la de porras (El desarrollador total) e incluso la última keynote de Obie fue sobre el mismo tema, aunque no comparto sus ideas y forma de trabajar ....

Por otra parte tuvimos la parte social con una apasionada e inspiradisima conferencia de Aitor García Rey (Hacks! Politics) y el entusiasmo de Rai hablando del Partido de Internet en una lighting talk.

Y no podía faltar la parte tecnológica, con mensajería y colas por Joshua Sierles (AMQP: Ruby en tiempo real), una introducción a CassandraDB por parte de Pablo Delgado (Cassandra DB: ¿Qué tienen Facebook, Twitter y Digg en común?), Raul nos contó sobre Rack y Sinatra (Alternativas a Rails para sitios y servicios web ultraligeros), John Leach explicando interesantes conceptos de unix (UNIX: Rediscovering the wheel), David Calavera nos enseñó como se especifica ruby gracías a RubySpec (Rubyspec y el largo camino hacia Ruby 1.9), Ron Evans aplicando Ruby y Arduino en el vuelo de dirigibles (Flying Robot), .... y paro aquí que al final voy a poner el listado completo de conferencias

Otro tema a destacar es la internacionalización de la conferencia. Este año ha habido muchas conferencias en inglés y ha desaparecido la coletilla 'Hispana' del nombre de la conferencia, supongo que ocupando parte del hueco que ha dejado la RailsConf Europe que organizaba O'Reilly.

En resumen, enhorabuena a la organización, que van mejorando año a año.

Nos vemos en la Conferencia Rails 2010 (si no aparece nada mejor que Rails el próximo año...)

jueves, 29 de octubre de 2009

Las webs y la televisión

Por variar un poco, una entrada de opinión

Siempre he tenido la idea de que una campaña de televisión sobre una web lo que consigue es montones de visitas mientras que se emite el anuncio y al desaparecer el anuncio, desaparecen las visitas. Si el producto es bueno, lo que conseguirá tráfico continuo es el boca a boca, entradas de blog, noticias online, comentarios de usuarios satisfechos con el producto....

Y hace poco he visto la confirmación de mi teoría. Zonzoo hizo una campaña en televisión este verano en la que se debió gastar una millonada, luego ha estado un par de meses sin campaña y ha vuelto a hacer otra.

Mirando el ranking en Alexa de zoonzo se ve que tal como subió desapareció y con la nueva campaña ha vuelto a aparecer.



Aunque el ranking Alexa no es fiable 100%, porque se basa principalmente en los datos de los usuarios que tienen la Toolbar Alexa, es un buen indicativo del tráfico y importancia de una web.

La idea es buena, y es probable que tengan éxito, pero en mi opinión habría sido mucho mejor hacer una buena campaña online y ofrecer mejores tarifas por los móviles, que les habría salido infinitamente más barato, y habrían crecido ordenadamente, consiguiendo tráfico y ingresos poco a poco

Y además, para soportar esa campaña habrán tenido que montar una buena infraestructura de servidores y logística que no habría sido necesaria inicialmente si hubieran apostado por el crecimiento lento y ordenado.

Bueno, no tengo ni idea de marketing y igual me equivoco, pero para eso están las opiniones, para equivocarse :)

martes, 20 de octubre de 2009

Evictions en memcached

En la aplicación en la que estoy trabajando tenemos memcached distribuido entre varias máquinas. Normalmente voy comprobando periódicamente que el tamaño usado sea menor al máximo tamaño disponible y lo teniamos configurado a 64 MB por máquina, ya que parecía suficiente.

En la traza se puede ver como tiene algo más de 40 MB (bytes) ocupados de los 64MB disponibles (limit_maxbtyes). El estado se puede consultar utilizando el método stats de la gema memcache-client o directamente haciendo un telnet al puerto donde está levantado tal y como contaba Jacobo hace unos meses en su blog:

bytes: 44140784
pid: 27269
connection_structures: 223
threads: 1
evictions: 215279
time: 1255950371
pointer_size: 32
limit_maxbytes: 67108864
cmd_get: 12315783
version: 1.2.2
bytes_written: 48564944477
cmd_set: 1505495
get_misses: 563019
total_connections: 643702
curr_connections: 61
curr_items: 15957
uptime: 9589358
get_hits: 11752764
total_items: 582809
rusage_system: 172.8108
rusage_user: 67.872241
bytes_read: 19210833034


Pero leyendo lo que significa cada uno de los parámetros de memcached en la web de escalabilidad de MySQL, me he dado cuenta de que el parámetro importante a comprobar es evictions. Eviction (que se puede traducir como desalojo), indica el número de elementos válidos de la caché borrados para liberar memoria para nuevos elementos y que debería ser cero o un número muy pequeño.

Así que hemos ampliado la memoria de memcached en todos los servidores a 128MB y efectivamente, nos habiamos quedado muy cortos.... ahora están ocupando sobre 90MB cada uno y a partir de ahora el parámetro a monitorizar es evictions :-)

Actualizacion 30/10/2009: Acabo de leer en Building Scalable Web Sites una forma alternativa de ver el status de memcached utilizando netcat. Suponiendo que está instalado en localhost en el puerto 11211

echo -ne "stats\r\n" | nc -i1 localhost 11211

Otra opción es utilizar memcache-top para ver las estadísticas en formato top (gracias a Paco por el enlace)

Actualizacion 16/10/2013:  Y cuatro años despues actualizo con otra forma de consultar los stats

/usr/share/memcached/scripts/memcached-tool localhost:11211 stats


miércoles, 7 de octubre de 2009

IE7 y IE8 con VirtualBox - Duplicar discos virtuales

Para probar las aplicaciones con Internet Explorer, hasta ahora tenía IE6 con ie4linux y IE7 con una máquina virtual de XP con VirtualBox

La instalación por defecto en Ubuntu es VirtualBox OSE (Open Source Edition) que no tiene soporte para USB, así que la que utilizo es la versión estándar tal y como explican en TuxGuides, para poder utilizar el software original de algunos perifericos en Windows.

El tema es que IE8 ya tiene una cuota de mercado lo suficientemente alta para probarlo todo tambien en IE8, por lo que me hacía falta otra máquina virtual. Claramente la opción crearla desde cero instalando de nuevo Windows, instalando n mil parches y reiniciando otras n mil veces no es buena opción, así que he investigado un poco como duplicar el disco ya existente.

Por defecto, los discos virtuales se crean en el directorio ~/.VirtualBox/HardDisks y tienen extensión .vdi, y desde línea de comando se pueden duplicar (en mi caso el disco anterior era WindowsXP y el nuevo es WindowsXP_IE8)

cd ~/.VirtualBox/HardDisks
diego@diego-laptop:~/.VirtualBox/HardDisks$ VBoxManage clonehd WindowsXP.vdi WindowsXP_IE8.vdi
VirtualBox Command Line Management Interface Version 2.2.4
(C) 2005-2009 Sun Microsystems, Inc.
All rights reserved.

0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: 8545bc77-6aa4-4594-b1a1-d1aa886abd40


Se toma su tiempo, pero una vez duplicado, simplemente creamos una nueva máquina virtual y en lugar de crear un nuevo disco seleccionamos el disco que acabamos de crear. Y una vez arrancado Windows simplemente actualizamos IE a la nueva versión y listo, ya tenemos las dos versiones para probar.

La configuración de la máquina virtual no se copia (memoria, usb, audio, ...), pero como es algo que se hace en 1 minuto no he perdido tiempo en ver como se haría automáticamente.

miércoles, 29 de julio de 2009

LinkedIn no me funciona

Hace un tiempo que LinkedIn me hacía cosas raras, sólo me mostraba algunas páginas y se me quedaba pensando eternamente en el resto de páginas al intentar cargarlas. Agustín me dió la solución, el culpable es el router D-Link DSL-G624T de ya.com, tal y como cuentan aquí.

El problema es debido a una regla que tiene definida el router con el tamaño máximo de segmento (MSS) y la solución que dan es borrarla.

Se puede conectar al router por telnet (con el mismo usuario que se accede al interfaz web), para ver todas las reglas

iptables -L -n
....
Chain FORWARD (policy ACCEPT) target prot opt source destination
TCPMSS tcp -- 0.0.0.0/0 0.0.0.0/0 tcp flags:0x06/0x02 TCPMSS set 1360 ....
.....

Y se debe borrar la primera regla de tipo FORWARD (que define el MSS)

iptables -D FORWARD 1

Borrando esa regla me funcionaba LinkedIn, pero empezó a dar problemas con otras web, p.e. las imagenes de ebay, que no me las cargaba. Así que opté por leerme el infernal man de iptables a ver que se contaba....

Parece ser que lo habitual es definir el tamaño máximo de segmento con un tamaño 40 bytes menor a la unidad máxima de transferencia (MTU) en lugar de un tamaño fijo como está asignando el router, y eso se puede hacer automáticamente con una regla de iptables

iptables -R FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Donde el -R FORWARD 1 indica que reemplace la primera regla de tipo FORWARD (la incorrecta) por esta.

El único inconveniente es que la regla se borra cada vez que se reinicia el router y se debe asignar de nuevo

ACTUALIZACION Nov. 2009: En los comentarios Jose Luis Domingo propone otra solución más elegante, donde la modificación se aplica sólo a los paquetes de linkedIn, no a todos los paquetes. Gracias !!!


Para quien le interese un poco más, la parte del man donde lo cuenta...

tcpmss
This matches the TCP MSS (maximum segment size) field of the TCP header. You can only use this on TCP SYN or SYN/ACK packets, since the
MSS is only negotiated during the TCP handshake at connection startup time.

[!] --mss value[:value]
Match a given TCP MSS value or range.

TCPMSS
This target allows to alter the MSS value of TCP SYN packets, to control the maximum size for that connection (usually limiting it to your
outgoing interface’s MTU minus 40 for IPv4 or 60 for IPv6, respectively). Of course, it can only be used in conjunction with -p tcp. It
is only valid in the mangle table.
This target is used to overcome criminally braindead ISPs or servers which block "ICMP Fragmentation Needed" or "ICMPv6 Packet Too Big"
packets. The symptoms of this problem are that everything works fine from your Linux firewall/router, but machines behind it can never
exchange large packets:
1) Web browsers connect, then hang with no data received.
2) Small mail works fine, but large emails hang.
3) ssh works fine, but scp hangs after initial handshaking.
Workaround: activate this option and add a rule to your firewall configuration like:
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu

--set-mss value
Explicitly set MSS option to specified value.

--clamp-mss-to-pmtu
Automatically clamp MSS value to (path_MTU - 40 for IPv4; -60 for IPv6).

These options are mutually exclusive.


martes, 7 de julio de 2009

Mechanize y content-type unknown

En una aplicación, tengo que integrar un informe que se no puede obtener a partir de un Web Service o REST ni nada parecido, así que la única forma es haciendo login en una web y navegando hasta bajarse un CSV. La integración se hace sin problemas con Mechanize, pero me he encontrado con que recibo estas cabeceras en la página del CSV:

Content-Type: unknown; charset=UTF-16LE
Content-Disposition: attachment; filename=report.csv


El problema está en la forma en que Mechanize parsea los datos recibidos. Decide que clase va a utilizar en función del Content Type. Para texto y html utiliza la clase WWW::Mechanize::Page, y si no sabe que utilizar, por defecto utiliza WWW::Mechanize::File.

En mi caso como no reconoce el Content-Type unknown, me devuelve un objeto de tipo WWW::Mechanize::File, a partir del cual no puedo parsear correctamente el CSV, ya que me devuelve un objeto binario sin ningún método fácil para procesarlo.

La primera solución que se me ocurrió a partir de la documentación de la clase PluggableParser es añadir unknown en la lista de Content-Type soportados por Page

agent.pluggable_parser['unknown'] = WWW::Mechanize::Page

Pero eso no vale, porque dentro de WWW::Mechanize::Page hay un chequeo adicional:

response['content-type'] =~ /^(text\/html)|(application\/xhtml\+xml)/i

Así que la solución para mi caso ha sido crearme una nueva clase que extiende a Page en la que su initialize es tan simple (y tan ñapa) como llamar a super y ignorar la excepción de content type inválido


require 'mechanize'
module WWW
class Mechanize
class Unknown < WWW::Mechanize::Page
def initialize(uri=nil, response=nil, body=nil, code=nil, mech=nil)
begin
super(uri, response, body, code)
rescue Mechanize::ContentTypeError
# Do nothing
end
end
end
end
end


Y hacer que el Content-Type unkown lo procese esta clase

agent.pluggable_parser['unknown'] = WWW::Mechanize::Unknown

Y con esto arreglado. Ya me devuelve un objeto que puedo parsear sin problema con FasterCSV.

viernes, 12 de junio de 2009

Epson DX8400 en Ubuntu

Como ya comenté en mi última entrada, lo que más guerra me dió al migrar a Ubuntu fue instalar la impresora multifunción Epson DX8400.

En la web de Epson te redirigen a Avasys para bajar los drivers. Seleccionando el modelo se pueden bajar los paquetes para la instalación. En mi caso pipslite_1.3.0-2_i386.deb para la impresora y iscan_2.19.2-1_i386.deb para el scanner

La impresora funciona perfectamente, pero lo del scanner es más divertido....

El paquete da un error de instalación ya que depende de libltdl.so.3 y en las últimas versiones de ubuntu se utiliza libltdl.so.7

Se puede arreglar simplemente con un link simbólico, como explican aquí:

sudo dpkg -i --ignore-depends=libltdl3 iscan_2.19.2-1_i386.deb
sudo ln -s /usr/lib/libltdl.so.7 /usr/lib/libltdl.so.3

El problema es que aunque con esto ya funciona el scanner, dejan de funcionar las actualizaciones automáticas de ubuntu, que dan un error de paquete roto. Y si le dices que lo arregle, desinstala iscan y te vuelves a quedar sin scanner.

Así que la solución es compilar el paquete para que utilice la librería correcta. Los fuentes se pueden bajar de la misma página donde está el paquete.

Mi primera opción fue el clásico make / configure / sudo make install.... pero como seguía sin reconocer el escáner, no tuve más remedio que hacer eso que sólo se hace en casos extremos.... leerme el README del paquete. En el README explica que se debe generar el paquete con

dpkg-buildpackage -rfakeroot

Y instalar el paquete generado

sudo dpkg -i iscan_2.19.2-1_i386.deb

Para poder compilar tuve que instalar unas cuantas librerias, que dependerán de lo que ya tengas instalado, en mi caso fueron:

sudo apt-get install gdk-imlib11-dev libsane-dev libgtk2.0-dev libgimp2.0-dev cdbs


Y esto si que funcionó y ya tengo el escáner funcionando como un campeón.

Por último unos cuantos comandos para chequear el escáner:

diego@diego-laptop:~$ lsusb |grep Epson
Bus 001 Device 022: ID 04b8:0839 Seiko Epson Corp. CX8300/CX8400/DX8400

diego@diego-laptop:~$ sane-find-scanner
found USB scanner (vendor=0x04b8, product=0x0839) at libusb:001:022

diego@diego-laptop:~$ scanimage -L
device `epkowa:usb:001:022' is a Epson Stylus CX8300/CX8400/DX8400 flatbed scanner

viernes, 29 de mayo de 2009

Adios Vista..... Hola ubuntu

Después de muchos años utilizando Windows como S.O. de trabajo, hasta hace un par de años por obligación y despues por la simplicidad de seguir utilizando lo mismo... llegó el momento de migrar a Ubuntu.

Inicialmente, la idea de este post antes de migrar era explicar los problemas que me he encontrara en la migración, que aplicaciones de Windows echaba en falta...

Pero la verdad es que después de una semana ubuntera no me he encontrado prácticamente con ningún problema, la práctica totalidad de las aplicaciones que uso en el día a día (Netbeans, Firefox, Thunderbird, Pidgin, Gimp, Thwirl, Filezilla, OpenOffice, ...) no es que funcionen igual, funcionan mejor y más rápido

Con respecto a la instalación, en Windows habría tardado 2 días en instalarlo todo, yendo de web en web para bajarme las diferentes aplicaciones (ruby, subversion, ...) y reiniciando n mil veces. En cambio en Ubuntu casi todo lo he podido instalar con Synaptic / apt-get y sin reiniciar ni una sóla vez.

Y además Spotify, que no tiene versión para linux, funciona perfectamente con wine :-)

Caso aparte el de los periféricos, la impresora multifuncion Epson DX-8400 no hubo manera de instalarla con los .deb que recomienda Epson y los tuve que compilar para que funcionaran, pero bueno, esto es tema para otro post...

lunes, 11 de mayo de 2009

Euruko 2009

Este fin de semana, junto a otros 250 desarrolladores he estado en la EuRuKo en Barcelona.

Hasta ahora mi relación con Ruby ha sido siempre en desarrollo web y asociado a Rails. Lo que más me ha gustado es ver como Ruby es mucho más que eso. Prácticamente ni se ha nombrado a Rails en toda la conferencia y hemos visto otras interesantes aplicaciones.

Con ruby se pueden hacer juegos con Gosu y Chipmunk como explico Javi en una de las conferencia más aplaudidas, se pueden procesar imágenes, hacer aplicaciones de telefonía con Adhearsion, desarrollos multiplataforma para móviles con Rhodes, hacer música de esa que yo nunca escucharía con Aarchaeopteryx, ....

Además tuvimos la keynote de Matz, una introducción a Cucumber por el padre de la criatura que me ha venido muy bien porque voy a empezar a usarlo en breve, y como broche final una impresionante y metálica introducción a D y a RuDy por Tomasz Stacheviwz , sin olvidarnos de las Lighting Talks.

En resumen, vuelvo con la sensación de que la conferencia ha valido la pena y con las pilas puestas para seguir aprendiendo y hacer las cosas un poco mejor día a día.

jueves, 30 de abril de 2009

Centrar verticalmente una imagen en un div

Aparentemente una cosa tan trivial como esa tiene un poco más de miga de lo que parece, y buscando soluciones se encuentran muchas divagaciones y ejemplos interminables.

La primera idea es usar el atributo vertical-align, pero sólo es válido para alinear la imagen con el texto adjacente. Sin embargo, se puede usar una solución simple basada ese atributo.

Si definimos el line-height del div igual a su altura y le ponemos un espacio en blanco delante de la imagen para que tenga una referencia donde alinearse, ya lo tenemos:

<div style="border: 1px solid #AA0000; text-align: center; line-height: 100px; width: 100px; height: 100px;">
&nbsp;<img style="vertical-align: middle;" src="http://www.blogger.com/logo.gif" />
</div>




Actualizacion 04/05/2009: Fer propone en los comentarios posibles alternativas a mi solución. Gracias!


Actualización 12/06/2009: He probado en Browsershots esta solución y los resultados son que funciona en

- Navegadores basados en Gecko (todas las versiones probadas de Firefox, Seamonkey, ...)
- Navegadores baseados en KHTML/Webkit (todas las versiones probadas de Konqueror, Safari, Chrome, ...)
- Todas las versiones de Opera a partir de la 7.54 incluida la 10 beta
- Internet Explorer 8.0

Y no funciona en:
- Versiones de IE inferiores a la 8.0 (7.0, 6.0, 5.5)
- Avant
- Dillo


Actualización 7/10/2009: En CodeProject dan una solución basada en javascript

Actualización 4/5/2011: 2 años después sigue dando guerra el mismo problema y en los comentarios apuntan un enlace que resuelve un caso particular. Gracias

http://www.jakpsatweb.cz/css/css-vertical-center-solution.html

martes, 31 de marzo de 2009

Memoria en Linux

Últimamente, el aumento de tráfico en una aplicación nos ha llevado a migrar de servidores para poder escalar con más facilidad.

Ayer por la tarde, mirando el estado de los nuevos servidores me encontré con esto en un free

$ free -m
total used free shared buffers cached
Mem: 2048 1996 51 0 599 364
-/+ buffers/cache: 1032 1015
Swap: 0 0 0

Y entré en modo semi-pánico porque tenía menos de un 5% de memoría libre y estos servidores virtualizados no tienen swap... pero investigando un poco y con la ayuda de Jacobo, encontré que la máquina está perfectamente, no estaba interpretando bien los datos.

buffers es la cantidad de memoria usada por el kernel para cachear I/O de disco y cached indica la memoría usada recientemente, pero que actualmente no está en uso y que está cacheada.

Así que la cantidad de memoría disponible en el servidor para aplicaciones es la suma de free + buffers + cached (la cantidad que pone en la columna free en la segunda fila), en el ejemplo 1.015 MBytes, casi el 50% de la RAM total.

Por último un enlace a un HowTo sobre la memoría en Linux, tiene sus añitos, pero es perfectamente válido

viernes, 23 de enero de 2009

Is Everyone Better Than You? Good!

Hace tiempo que tenía ganas de leer algún libro técnico 'filosófico', que hablará más sobre la forma de trabajar y buenas prácticas que sobre programación sin más.

En la Conferencia Rails, Sergio Gil en su charla recomendó un par de libros, y finalmente me he comprado Practices of an Agile Developer. Supongo que tarde o temprano tambien me acabaré leyendo el otro (The Pragmatic Programmer)

No habla de nada revolucionario ni reinventa la rueda, pero te explica todo eso que ya sabes y que no siempre aplicas. Y después de leerlo dan ganas de intentar hacer las cosas un poco mejor, que era mi objetivo al leerlo

El libro tiene una frase que me ha gustado mucho y que he puesto de título en esta entrada

Is Everyone Better Than You? Good!

Ya que me he sentido muy identificado tanto con esa frase como con el parrafo que viene despues en el libro. Viniendo de la tierra de los ciegos donde el tuerto era el rey, cuando empecé a trabajar en ASPgems, una de las cosas que más me gusto fue ese sentimiento de 'soy el más torpe de todos, cuanto por aprender!!!'

Y el día que ya no me pase... pues me tendré que plantear cambiar de trabajo :)