Noticias Weblogs Foros Wiki Código

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Sponsors

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin

Javier Pérez

Cómo promocionar un blog: Usabilidad

Noviembre 21st, 2011 - [Enlace local]

Cómo promocionar un blog

ÍNDICE

0. Introducción
1. SEO
2. SEM
3. Social Media
4. Emailing
5. Usabilidad
6. Analítica Web
7. Afiliación

Usabilidad

La usabilidad es el arte de hacer que tu blog (o cualquier otro tipo de interfaz) sea fácil de usar (en el caso de un blog, incluido que sea fácil de leer). En este ámbito entran los colores, la disposición de los contenidos, los tamaños de letra, el tiempo de carga de la página, etc. Todo lo que tenga que ver con la interacción interfaz-usuario, de ahí que también se conozca como UX (User eXperiencie, experiencia de usuario).

La imagen que encabeza este artículo me encanta, a golpe de vista puedes ver que la usabilidad se consigue como un punto de unión entre diseño, sentido común, y simplicidad.

La usabilidad da para mucho más que un simple artículo en esta serie, y tiene que ver más con la psicología que con cualquier otro área. Pero para simplificar, lo que te aconsejo es que uses tu sentido común, y sobre todo tu empatía (empatía, dícese de la capacidad de ponerte en el lugar de los demás). Por ejemplo, puedes pensar que poner un reloj Flash en la cabecera de tu blog queda muy chupiguay, pero en cuanto usas el sentido común y la empatía te das cuenta de que eso no le interesa a nadie más que a ti. Por experiencia personal sé que la empatía no se produce de forma natural, sino que hay que entrenarla (depende de cada persona). Un buen ejercicio es inventarte un personaje (por ejemplo, imagina que eres tu abuelo) y tratar de usar la web poniéndote en su lugar (intereses, conocimientos técnicos, visibilidad, tamaño del monitor que usa para ver la web, etc.).

La situación de los contenidos es muy importante en este sentido. Un ejemplo es el listado de artículos relacionados de este blog. Cuando un lector termina de leer uno de mis artículos, probablemente le interese leer otro de temática relacionada, de ahí que esté al final del artículo y no antes. Este es un caso de contenido extra que cumple tres normas fundamentales:

  1. Es útil para el usuario.
  2. No molesta a quien no le interese.
  3. Está situado en el punto más adecuado.

Como puedes ver, tu reloj Flash chupiguay no cumple ninguna.

En el comercio electrónico la usabilidad es fundamental. Si un usuario, posible cliente, quiere comprar un artículo, pero no encuentra fácilmente el botón de comprar, no dedicará demasiados esfuerzos a encontrarlo, sino que cerrará la pestaña y abrirá otra para buscar el producto en otra tienda online.

Llegar a conocer la mejor ubicación para cada elemento es una tarea muy difícil, y va más allá del sentido común que pueda tener cada uno. Por ese motivo se inventaron los tests A/B. Estos tests consisten en crear varias versiones de una misma página web, donde se modifican ligeramente los colores, tamaños, textos y disposición de los elementos, como pueda ser este ejemplo, colocando el botón de comprar en varias posiciones distintas. La plataforma que realice estos tests (Google Optimizer, por ejemplo) mostrará al usuario una versión u otra de forma aleatoria, y al final del periodo estipulado te indicará qué versión obtuvo más éxito, es decir, con qué versión se consiguieron más ventas. En el caso de un blog sin aspiraciones de venta, hacer este tipo de trabajo sería realmente estúpido, pero al menos deberías conocer su existencia.

Estos son mis consejos básicos para que apliques usabilidad en tu blog:

  1. Usa un diseño claro, fondo blanco con letras en tono oscuro, con un tipo de letra normal (arial, verdana, tahoma, times roman…).
  2. Usa un mismo tono de color para todos tus enlaces y que se distinga perfectamente del resto de textos. No te olvides de usar un estilo a:visited para marcar de otro tono de color los enlaces visitados. El subrayado no es importante si los enlaces son fácilmente reconocibles, aunque siempre es recomendable usarlo.
  3. Usa tamaños de letra grandes para el artículo (título y contenido) y más pequeños para el resto de contenidos (bloques laterales).
  4. No uses animaciones GIF, y mucho menos Flash.
  5. Pon en tu blog sólo lo que el usuario necesite o le interese. Evita banners superiores enormes que obligan a hacer scroll para llegar al contenido.

Por último podemos incluir aquí la velocidad de carga de página. Ningún esfuerzo que hagas será tan agradecido como que tu página se cargue lo más rápido posible. Si puedes permitirte un servidor (hosting) más rápido te aconsejo que lo contrates ya. Y en cualquier caso es importante que instales algún servicio de cacheo que aumente la velocidad de carga, y además te servirá para evitar la caída de tu blog ante un posible efecto menéame. Para WordPress tienes el plugin WP Super Cache (bastante complejo), pero hay muchísimos más.

También dispones de la herramienta Google Page Speed, con la cual puedes comprobar tu velocidad de carga actual y cómo conseguir aumentarla. Una herramienta que se está convirtiendo en imprescindible y a la que al menos deberías echarle un buen vistazo.

En el siguiente artículo veremos un poco de analítica web, importantísimo para conocer qué es lo que buscan y quieren tus lectores.

» Leer más, comentarios, etc...

Koalite's blog

¿Se puede hacer DDD sin un experto en el dominio?

Noviembre 21st, 2011 - [Enlace local]

TL;DR: es difícil, pero aunque no tengas un experto a mano, hay partes del proceso que siguen siendo útiles.

La mayoría de artículos sobre DDD que leo últimamente, y especialmente en blogs en español, se centran en los detalles de implementación, que no dejan de ser algo anecdótico. Parece que el objetivo de DDD es estructurar nuestro código en Entities, ValueObjects, Repositories, Factories, etc. Nos centramos en ver cómo ha de ser la estructura de proyectos de Visual Studio, y parece que cuantos más proyectos diferentes tenga, mejor. Como mucho, si somos Advanced Power Certified Architects ™, podemos hablar un poco de Bounded Contexts o incluso de Shared Kernels.

Sin embago, lo más importante de DDD, su esencia, sólo se menciona de pasada (si hay suerte). Si DDD es Domain Driven Development, es decir, Desarrollo Dirigido por el Dominio, parece claro que lo más importante de todo, lo que dirige nuestro desarrollo, es el dominio, que podríamos definir como el ámbito para el cual estamos desarrollando la aplicación.

¿Por qué necesitamos un experto en el dominio?

En general nosotros, el equipo de desarrollo, no conocemos mucho de este ámbito, sobre todo al principio. Necesitamos alguien que nos enseñe lo que es el dominio. Alguien que discuta con nosotros, que nos explique lo que sabe, los problemas a los que se enfrenta y la forma en que los resuelve.

Distintos Modelos de Dominio de Mapas, por XKCD

Distintos modelos de un mismo dominio: la cartografía (XKCD.com)

Una parte fundamental de nuestra labor será crear un modelo que nos permita manipular fácilmente ese dominio en nuestra aplicación, pero no es sencillo elegir ese modelo. Habrá muchos modelos posibles y cada uno tendrá sus ventajas, pero tendremos que decidir cuál es el que mejor se ajusta a los problemas que tenemos que resolver.

La persona que nos tiene que ayudar a conseguirlo es el experto en el dominio. Es quien realmente conoce la realidad y es quien nos puede ayudar a validar los modelos que vamos creando. El experto en el dominio desempeña un rol fundamental en el desarrollo de la aplicación.

¿Se puede hacer algo sin él?

Por desgracia, hay ocasiones en que tenemos que afrontar un proyecto y no podemos contar con un experto en el dominio para guiarnos. ¿Debemos descartar entonces el uso de DDD? Lo más probable es que sí, pero hay partes del proceso que siguen siendo útiles. Además, si se trata de un proyecto de largo recorrido, como puede ser un producto estándar (en lugar de un desarrollo a medida para un cliente concreto), puede ser interesante que nosotros mismos nos acabemos convirtiendo en expertos en el dominio.

Es necesario tener en cuenta que convertirse en experto en cualquier cosa no es fácil y requiere una inversión de esfuerzo y tiempo considerable. No obstante, si estamos desarrollando un producto estándar realmente no nos queda más remedio que asumir ese rol. Podremos contar con la ayuda de algunos usuarios y su siempre importante opinión, pero rápidamente nos daremos cuenta de que cada potencial usuario de la aplicación tiene su propia idea de como deben ser las cosas, por lo que al final será labor nuestra unificar sus ideas y buscar una solución que sea útil y cómoda al mayor número posible de usuarios. Para poder llegar a eso, es necesario un cierto conocimiento del dominio.

OJO: Cuando hablo de nosotros me refiero al equipo encargado del proyecto, incluyendo la gente de desarrollo, el product manager, el product owner, el analista que pasaba por allí, el arquitecto enamorado del UML, los consultores de 500€/hora y la señora de la limpieza. No pretendo decir que todo sea responsabilidad de los que desarrollamos.

Si en lugar de un producto estándar estamos en un proyecto de poco tiempo de duración, que no se espera que evolucione demasiado en el tiempo y cuya lógica de negocio no es completa, directamente no importa si hay experto en el dominio o no. No uses DDD, pero por muchas otras razones.

De todas formas, hay partes de DDD como proceso que son útiles y que se pueden aplicar incluso aunque tengamos que ponernos nosotros en el papel de expertos sin serlo realmente.

La idea de crear un lenguaje ubicuo que nos ayude a modelar la realidad y, lo que es más importante, a dialogar sobre ella de una forma precisa, es muy útil, aunque sólo sea para la comunicación interna del equipo. Además esto nos ayuda a ponernos en la piel del usuario, intentar entender cómo piensa, a qué problemas se enfrenta y cómo resolverlos. De esta forma podremos resolver lo que realmente preocupa al usuario y crearemos un modelo pensado para resolver esos problemas y no otros.

También resulta útil intentar crear un modelo de dominio rico, siguiendo los patrones típicos de DDD (Entities, Repositories, …), tratando de encapsular toda la lógica posible en las entidades, aislando las partes externas al sistema mediante interfaces e inversión de dependencia y creando capas anticorrupción para protegernos en los puntos de integración. Con ello conseguiremos también una aplicación más sencilla de testear con test unitarios.

Esto no es DDD

Esto no es DDD

En el fondo, muchas de esas cosas no son más que buenas prácticas genéricas de todo desarrollo de software y, en concreto, de programación orientada a objetos.

Lo que no tiene sentido es lanzarse ciegamente una y otra vez a seguir ejemplos de arquitecturas complejas que no tienen nada que ver realmente con DDD.

DDD es un proceso, no una arquitectura.

Compartir enlace:
Facebook Twitter Email

» Leer más, comentarios, etc...

Escuela De Codigo

Instalación desatendida de WordPress

Noviembre 21st, 2011 - [Enlace local]

Cuando me encomiendan desarrollar una pagina web, lo primero que se me viene a la mente es WordPress, asi que de inmediato me pongo a configurar una nueva instalación de este famoso gestor de contenido, el proceso basicamente es el siguiente: descargar la ultima versión estable del sitio oficial, crear la base de datos, crear el usuario de base de datos, darle permisos a este usuario sobre la base recién creada, descomprimir WordPress en la carpeta de mi Apache, crear el archivo de configuración para este nuevo sitio, agregar la dirección a mi archivo de hosts, reiniciar Apache, instalar WordPress. Un proceso de lo mas aburrido, tedioso, y repetitivo. Tenia que acabar con esa pequeña tortura en mi vida. ¿Como lo hice? A continuación el proceso.

¿Que vamos a necesitar?

Paso 0 : Conocer el mundo de Ruby

Al igual que el tutorial anterior es esencial que conozcas lo basico de Ruby

Paso 1: Descargar versión estable de WordPress

Antes de querer instalar WordPress, debemos descargarlo del sitio oficial, la versión estable y guardarlo en alguna carpeta temporal de nuestro sistema

#Creo directorio temporal para descargar el wordpress
FileUtils.mkdir "/tmp/wordpress"
#Descargo el wordpress estable
puts "Downloading Wordpres... "
attachment_file = "/tmp/wordpress/latest.zip"
open(attachment_file, "wb") do |file|
file.print open("http://wordpress.org/latest.zip").read
end

Pero, esta es la versión en ingles yo quiero el ultimo WordPress en español

Para tal proposito modificamos nuestro script para que se vea así

agent = Mechanize.new
#Si el lenguaje que vamos a usar es el Español, usamos este truco para poder construir la direccion de descarga
if language == 'es'
page = agent.get('http://core.svn.wordpress.org/tags/')
last_version = page.links[page.links.length - 2].to_s[0..(page.links[page.links.length - 2].to_s.length - 2)]
source_url = "http://es.wordpress.org/wordpress-#{last_version}-es_ES.zip"
else
source_url = "http://wordpress.org/latest.zip"
end
#Creo directorio temporal para descargar el wordpress
FileUtils.mkdir "/tmp/wordpress"
#Descargo el wordpress estable
puts "Downloading Wordpres... "
attachment_file = "/tmp/wordpress/latest.zip"
open(attachment_file, "wb") do |file|
file.print open(source_url).read
end

Paso 2: Descomprimir WordPress recién descargado

Para esto haremos uso de la gema zipruby

puts "Unzipping Wordpres..."
#Descomprimo archivo recien descargado
Zip::Archive.open("/tmp/wordpress/latest.zip") do |ar|
ar.each do |zf|
if zf.directory?
FileUtils.mkdir_p("/tmp/wordpress/"+zf.name)
else
dirname = File.dirname("/tmp/wordpress/"+zf.name)
FileUtils.mkdir_p(dirname) unless File.exist?(dirname)
open("/tmp/wordpress/"+zf.name, 'wb') do |f|
f << zf.read
end
end
end
end

Paso 3: Crear la base de datos

Hay varias formas de ejecutar procesos del sistema operativo pero, en esta ocasión lo haremos con este método

puts "Creating Wordpress database..."
#Creo base de datos y usuario de acceso
IO.popen("mysqladmin -p#{mysqlrootpass} create \"#{dbname}\"")
IO.popen("echo \"GRANT ALL PRIVILEGES ON #{dbname}.* TO #{dbuser}@localhost IDENTIFIED BY '#{dbpassword}';\" | \mysql -u root -p#{mysqlrootpass}")
[/ruby]

Paso 4: Mover los archivos al directorio Apache

 

En una instalación por defecto de Apache, los archivos públicos generalmente se encuentran en el directorio /var/www asi que moveremos los archivos hacia ahí

[ruby] puts “Moving WordPress to Apache directory…” #Muevo el archivo al directorio de apache FileUtils.mv(“/tmp/wordpress/wordpress”, “/var/www/#{domain}”) #Y de paso borramos la carpeta que ya no la utilizaremos FileUtils.rm_r(“/tmp/wordpress”)

Paso 5: Crear archivo wp-config.php

El archivo wp-config.php es donde colocamos los datos de conexión a la base de datos, completamente necesario para una exitosa instalación de WordPress

#Creo el archivo de instalacion con los datos de conexion a la base de datos
FileUtils.mv("/var/www/#{domain}/wp-config-sample.php", "/var/www/#{domain}/wp-config.php")
text = File.read("/var/www/#{domain}/wp-config.php")
File.open("/var/www/#{domain}/wp-config.php", 'w') do |f|
if language == 'es'
f.puts text.gsub(/nombredetubasededatos/, "#{dbname}").gsub(/nombredeusuario/, "#{dbuser}").gsub(/contraseña/, "#{dbpassword}")
else
f.puts text.gsub(/database_name_here/, "#{dbname}").gsub(/username_here/, "#{dbuser}").gsub(/password_here/, "#{dbpassword}")
end
end

Paso 6: Crear archivo de configuración de Apache

Como agregar un sitio nuevo en nuestro Apache es un tema completamente diferente, asi que no me detendre en eso aquí

#Creo el archivo de configuracion de apache
File.open("/etc/apache2/sites-enabled/#{domain}.conf", 'w') do |f|
f.puts "<VirtualHost *:80>
ServerAdmin #{email}
DocumentRoot /var/www/#{domain}/
ServerName #{domain}
ServerAlias www.#{domain}
<Directory>
Options FollowSymLinks
AllowOverride All
</Directory>
<Directory /var/www/#{domain}>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
</VirtualHost>"
end

Paso 7: Agregar el nuevo sitio al archivo de hosts

Es mas fácil recordar un dominio que una dirección del tipo http://localhost/blog-de-nuevo-cliente-que-aun-no-me-paga ¿no?

File.open("/etc/hosts", 'a') do |f|
f.puts "127.0.0.1 #{domain}"
end

Paso 8: Reiniciar Apache

Y para que el nuevo sitio sea detectado, reiniciamos el Apache

puts "Restarting Apache... "
#reinicio apache
`/etc/init.d/apache2 restart` #Aqui espera hasta que termina el comando para continuar

Paso 9: Instalamos WordPress!!!

Y finalmente, invocamos el instalador de WordPress

puts "Installing Wordpress..."
agent.post("http://#{domain}/wp-admin/install.php?step=2",
{
"Submit" => "Install WordPress",
"blog_public" => "0",
"weblog_title"=>"",
"user_name"=>"#{dbuser}",
"admin_password"=>"#{dbpassword}",
"admin_password2"=>"#{dbpassword}",
"admin_email"=>"#{email}",
}
)

Aquí esta el script completo

# encoding: utf-8
require 'open-uri'
require 'fileutils'
require 'zipruby'
require 'mechanize'
 
domain = "tudominio.com"
email = "tuemail@gmail.com"
mysqlrootpass = "tumysqlrootpassword"
language = "es"
 
o = [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten;
password = (0..13).map{ o[rand(o.length)] }.join;
 
dbuser = domain.split('.')[0][0..15]
dbname = domain.split('.')[0]+"_"+domain.split('.')[1]+"_db"
dbpassword = password
 
agent = Mechanize.new
 
if language == 'es'
page = agent.get('http://core.svn.wordpress.org/tags/')
last_version = page.links[page.links.length - 2].to_s[0..(page.links[page.links.length - 2].to_s.length - 2)]
source_url = "http://es.wordpress.org/wordpress-#{last_version}-es_ES.zip"
else
source_url = "http://wordpress.org/latest.zip"
end
 
#Creo directorio temporal para descargar el wordpress
FileUtils.mkdir "/tmp/wordpress"
#Descargo el wordpress estable
puts "Downloading Wordpres... "
 
attachment_file = "/tmp/wordpress/latest.zip"
open(attachment_file, "wb") do |file|
file.print open(source_url).read
end
 
puts "Unzipping Wordpres... "
#Descomprimo archivo recien descargado
Zip::Archive.open("/tmp/wordpress/latest.zip") do |ar|
ar.each do |zf|
 
if zf.directory?
FileUtils.mkdir_p("/tmp/wordpress/"+zf.name)
else
dirname = File.dirname("/tmp/wordpress/"+zf.name)
FileUtils.mkdir_p(dirname) unless File.exist?(dirname)
open("/tmp/wordpress/"+zf.name, 'wb') do |f|
f << zf.read
end
end
end
end
 
puts "Creating Wordpress database... "
#Creo base de datos y usuario de acceso
IO.popen("mysqladmin -p#{mysqlrootpass} create \"#{dbname}\"") { |f| }
IO.popen("echo \"GRANT ALL PRIVILEGES ON #{dbname}.* TO #{dbuser}@localhost IDENTIFIED BY '#{dbpassword}';\" | \mysql -u root -p#{mysqlrootpass}") { |f|
}
 
puts "Moving Wordpress to Apache directory... "
#Muevo el archivo al directorio de apache
FileUtils.mv("/tmp/wordpress/wordpress", "/var/www/#{domain}")
 
FileUtils.rm_r("/tmp/wordpress")
 
#Creo el archivo de instalacion con los datos de conexion a la base de datos
FileUtils.mv("/var/www/#{domain}/wp-config-sample.php", "/var/www/#{domain}/wp-config.php")
text = File.read("/var/www/#{domain}/wp-config.php")
File.open("/var/www/#{domain}/wp-config.php", 'w') do |f|
if language == 'es'
f.puts text.gsub(/nombredetubasededatos/, "#{dbname}").gsub(/nombredeusuario/, "#{dbuser}").gsub(/contraseña/, "#{dbpassword}")
else
f.puts text.gsub(/database_name_here/, "#{dbname}").gsub(/username_here/, "#{dbuser}").gsub(/password_here/, "#{dbpassword}")
end
end
 
#Creo el archivo de configuracion de apache
File.open("/etc/apache2/sites-enabled/#{domain}.conf", 'w') do |f|
f.puts "<VirtualHost *:80>
ServerAdmin #{email}
DocumentRoot /var/www/#{domain}/
ServerName #{domain}
ServerAlias www.#{domain}
<Directory />
Options FollowSymLinks
AllowOverride All
</Directory>
<Directory /var/www/#{domain}>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
</VirtualHost>"
end
 
File.open("/etc/hosts", 'a') do |f|
f.puts "127.0.0.1 #{domain}"
end
 
puts "Restarting Apache... "
#reinicio apache
`/etc/init.d/apache2 restart` #Aqui espera hasta que termina el comando para continuar
 
puts "Installing Wordpress... "
agent.post("http://#{domain}/wp-admin/install.php?step=2",
{
"Submit" => "Install WordPress",
"blog_public" => "0",
"weblog_title"=>"",
"user_name"=>"#{dbuser}",
"admin_password"=>"#{dbpassword}",
"admin_password2"=>"#{dbpassword}",
"admin_email"=>"#{email}",
}
)
 
puts "****** Successful Wordpress Installation ******"
puts "-> Domain: http://#{domain}"
puts "-> Username: #{dbuser}"
puts "-> Password: #{password}"

Ahora para disfrutar solo queda correrlo como usuario root o usando sudo y en menos de un minuto tendras tu WordPress completamente listo y sin despeinarte!

Extra: Regalo para los que tienen prisa

Basado en el código fuente de este tutorial cree una pequeña gema para hacer aun mas fácil el proceso de instalación de WordPress.

wpinstaller-0.0.1.gem

» Leer más, comentarios, etc...

Viricmind Labs

Litipk

Noviembre 18th, 2011 - [Enlace local]

Litipk RobotEste año el Concurso Universitario de Software Libre vuelve a la carga (esta es ya su sexta edición). Yo me presento por enésima vez, a ver si por fin consigo acabar lo que empiezo :) (sí, quiero acabar, no ganar).

El proyecto que presentaré se llama Litipk, y a mi entender será mucho más modesto y humilde que las barbaridades que "intenté" en las otras ediciones del concurso. Evidentemente eso hace que tenga menos posibilidades de ganar debido a la falta de innovación, pero mi gran propósito es ofrecer algo a la comunidad que pueda empezar a resultar útil a corto plazo.

¿Qué "será" Litipk?

Litipk "será" una aplicación web dirigida a facilitar la búsqueda, catalogación y compartición de material didáctico online, haciendo especial incapié en el aspecto social y comunitario. Mi deseo es conseguir que la gente se ayude mutuamente a la hora de intentar aprender :) .

¿Por qué Litipk?

Desde hace tiempo la red se está llenando de cursos, tutoriales, vídeos, libros y muchos otros recursos didácticos o formativos. Quien quiere aprender puede hacerlo sin demasiados problemas, pero eso sí, probablemente perderá un tiempo precioso buscando material, tiempo que podría ahorrarse si facilitamos un poco las cosas :) .

Por otro lado, hay un factor importantísimo que me ha motivado a decidirme por este proyecto: la crisis económica. Cada día vemos más recortes en el sector de la educación, ya sea en educación primaria, secundaria obligatoria, bachillerato, formación profesional o las mismas universidades.

Hay muchos potenciales estudiantes que no han podido encontrar plaza allí donde creían oportuno formarse, y otros simplemente no tienen la posibilidad económica de costearse los estudios. Y aunque eso ya debería ser suficiente, pues la educación y la formación tienen valor por sí mismas, es importante destacar también que la economía depende fuertemente de la formación de la ciudadanía. Es por eso que pensé en aportar mi pequeño granito de arena.

Algunos apuntes más

Litipk será desarrollado en CoffeeScript , haciendo uso de NodeJS y una buena lista de librerías y microframeworks libres. Tengo que admitir que a nivel técnico no es una decisión demasiado acertada, es cierto que puedo conseguir resultados espectaculares en cuanto a rendimiento, pero también lo es que trabajaré el doble para conseguir lo que podría hacer con Symfony2 o CakePHP. Sea como sea mi decisión está tomada, y lo que me ha motivado a tomar este rumbo es mi tendencia a probar cosas nuevas :) .

Respecto al blog, esta vez he decidido no crear un blog aparte para el proyecto. Todas las entradas estarán en mi blog personal, Viricmind Labs, pero bajo la etiqueta Litipk. Lo hago así para evitar dispersar demasiado mi atención y poder controlar mejor el histórico de mi trabajo.

Para finalizar, quiero decir también que Litipk ya tiene algo parecido a un logotipo :) , se trata del robot que podéis ver en este mismo artículo. El dibujo es obra de Cristina Pérez (aunque yo la llamo Pistacho), y está licenciada bajo Creative Commons 3.0 By-Sa .

» Leer más, comentarios, etc...

El blog de pico.dev

Personalizar GNOME (iconos, temas, extensiones, opciones)

Noviembre 18th, 2011 - [Enlace local]

GNOME
Arch Linux
Una vez que tenemos instalado nuestro sistema una de las primeras cosa que solemos hacer es personalizarlo cambiando el fondo de pantalla, instalando un pack de iconos o cambiando el tema de las ventanas. Aunque GNOME con su versión 3.0 o 3.2 ha perdido algunas funcionalidades y algunas posibilidadesd de configuración la herramienta gnome-tweak-tool permite configurar las opciones más habituales que querrán la mayoría de los usuarios. Para instalarla en arch linux:



# pacman -S gnome-tweak-tool


Una vez instalada veremos su icono en el menu Aplicaciones > Accesorios > Configuración avanzada.



En la pestaña Escritorio podemos configurar algunos comportamientos como mostrar la visibilidad de los iconos Computadora, Papelera, Carpeta Home.





En Extensiones de GNOME-Shell podemos instalar nuevas extensiones que descarguemos aunque es mejor opción hacerlo con el gestor de paquetes de nuestra distribución. Hay una lista de extensiones disponibles para Arch linux que pueden instalarse individualmente y que modifican el comportamiento por defecto del shell de gnome.





En GNOME-Shell podemos personalizar la información que se muestra en el reloj, las acciones a realizar al cerrar la tapa del portátil y los botones que queremos en las ventanas.





En Tema podemos configurar los temas del puntero del ratón, iconos, tema de los componentes GTK+ y de las ventanas. Uno de los temas de iconos más conocidos es el tema faenza disponible en Arch linux en el repositorio AUR con el nombre de paquete faenza-icon-theme. Aunque temas de iconos hay muchos.





En Tipografías se pueden cambiar las fuentes y tamaños de la fuente usada en el sistema, de los documentos, en el título de la ventana y alguna otra opción.





En la opción Ventanas se pueden modificar algunos comportamientos al hacer clic en las ventanas.





La falta de configuración de la versión 3 de gnome es una de las críticas que se le ha hecho pero a medida que vaya evolucionando en versiones lo hará al mismo tiempo en funcionalidades y opciones de configuración, es cuestión de tiempo.



Yo no soy de tener una personalización extrema del escritorio prácticamente tengo con la configuración por defecto exceptuando el tema de iconos faenza.







» Leer más, comentarios, etc...

Cuaderno de software

¡Carlos Ble en DoNewTech!

Noviembre 18th, 2011 - [Enlace local]

Ésta semana en DoNewTech hemos podido disfrutar de la presencia de Carlos Ble como Agile Coach. Como tal, su objetivo no era tanto darnos una formación al uso o hacer un trabajo de consultoría sino, en cierta manera, darnos un punto de vista externo sobre cómo desarrollamos software aquí, sentarse con nosotros para mejorar nuestro kung-fu TDDista y ayudarnos a catalizar una serie de pasos necesarios para caminar hacia una mayor interiorización de las prácticas XP y del agilismo.

Personalmente, lo que más me ha gustado ha sido su trabajo como “catalizador”. Tras su estancia aquí:

Además, Carlos nos reunió durante diversas ocasiones a lo largo del coaching. Insistió en algo que, aunque resulta básico, hay que tenerlo siempre claro: el cambio que estás esperando, eres tú: hizo una llamada a nuestra responsabilidad como profesionales a la hora de realizar nuestro trabajo, y  a nuestra capacidad de ejecución (demasiado “deberíamos hacer” y muy poco hacer de verdad).
Quizá una de las cosas que más nos sorprendió a todos es que nos comentara que no intentáramos hacer scrum porque no estábamos preparados. Nos aconsejó montar un kanban enorme (tamaño pared entera) que representara visualmente el status TOTAL del proyecto, y en el que nos concentráramos en intentar añadir valor semanalmente. Congelar los requisitos durante todo un sprint de por ejemplo tres semanas, es algo demasiado difícil para nosotros actualmente. Y nos desenfoca del objetivo.
También me gustó mucho que enfocara todo a dinero, esto es: hacer o no hacer un refactor es cuestión principalmente de si resulta demasiado caro o no para el cliente, no de qué queramos código más bello o poético.
A parte de las acciones de cambio que hemos realizado durante la semana, salimos con una serie de ideas a implementar cuanto antes (ésta vez sí  :-)):

Para celebrar lo estupenda que había sido la semana, terminamos con un estupendo Coding Dojo que Carlos facilitó junto a Rubén Bernardez. Carlos tuvo la deferencia de ponerse la camiseta de Hello kata que le habíamos regalado los programaníacos cuando lo visitamos en Canarias. No sé por qué su novia no deja que se la ponga… :-P

Por último dejo una foto de Carlos enfrentándose a un bocata vasco (aquí conocido como “trainera”). Realmente la foto es un poco fake, porque Carlos nunca comería lomo… :-)

 

 


» Leer más, comentarios, etc...

carlosrovira.com

Flex: Un futuro más brillante que nunca

Noviembre 17th, 2011 - [Enlace local]

Acabo de leer la nueva entrada de Michael Chaize, evangelista de Adobe, sobre todos los cambios que afectan a Flex y me parece una lectura obligada para todos los que trabajamos con dicha tecnología en aplicaciones empresariales.

Por fin leo una exposición que viene de alguien de Adobe y que explota el problema desde el lado puramente empresarial que es el verdadero nicho de las aplicaciones Flex.

Michael da justo en el clavo y nos hace ver lo que yo y otros muchos hemos intentado comunicar a Adobe una y otra vez sin éxito debido sencillamente a los objetivos claramente distintos de Adobe (la venta de herramientas para el tratamiento de contenidos) y de las empresas que adoptan Flex para sus soluciones empresariales (sistemas empresariales cuya construcción está subyugada a entornos de integración continua donde se deben integrar con otras muchas soluciones open source, donde la orientación a objetos es crucial, donde nunca ha sido crucial tener un “Design View”, pero si un plugin de maven-flashbuilder y donde la naturaleza de la propia empresa es muy distinta a la del usuario *de la calle* donde HTML5 está teniendo tanto éxito en móviles y tablets).

Está claro que el caso que yo me esfuerzo en defender, el de las aplicaciones empresariales, afecta a un colectivo muy concreto, al cual no puedes ofrecerle una visión irreal o utópica. El mundo de la empresa se mueve en otros tiempos (quizá tiempo bala, como en Matrix ;) ) y con objetivos claros de fiabilidad, seguridad y alta disponibilidad. Suele tener además implicaciones muy distintas a las pequeñas soluciones que se manejan en internet (cualquier servicio en internet suele ser ordenes de magnitud más pequeño, manejable y mantenible a nivel de desarrollo).

En definitiva, muchos de los casos de uso a los que me refiero yo y donde Flex se utiliza de forma brutalmente extensiva, son aplicaciones privadas, que viven dentro del entorno de la empresa, en redes privadas o intranets, cuyo acceso es privado y ciclo de vida y necesidades son muy distintos a los que podemos encontrar en el mundo al que Google, Apple y ahora Adobe se quieren dirigir de forma exclusiva.

Lo nuestro siempre ha sido un escenario donde Apache, Java, Spring, y otras muchas organizaciones han sido las que han marcado las aplicaciones. Adobe Flex siempre ha sido una tecnología con un aporte claro y necesario pero con una naturaleza extraña por estar dentro del ala de Adobe, y que ahora por fin puede ocupar su lugar natural junto con el resto de soluciones del sector en Apache.

Creo que esta es una lectura obligada y que a todos los que estáis en un entorno empresarial similar a mí os va a gustar y vais a ver que por fin alguien de Adobe “habla vuestro mismo idioma”.

Enhorabuena Michael! :D

» Leer más, comentarios, etc...

Picando Código

Legibilidad

Noviembre 17th, 2011 - [Enlace local]

En la RubyConf conocí personalmente a DrummerHead, diseñador y desarrollador front-end. Al visitar el blog, notó que la legibilidad se podía mejorar:

Lo mas importante de un blog es el contenido y en su mayoría el contenido es texto :P entonces la legibilidad es muy importante.
DrummerHead – 2011

Me mandó un código CSS para mejorar un poco el tema, que ya estoy aplicando en el CSS de Picando Código. ¡Comenten qué les parece! Creo que mejoró bastante…

Con este post agradezco el aporte de DrummerHead, aunque creo que los más beneficiados van a ser los que lean el blog desde el sitio. El diseño está propenso al cambio constante, así que cualquier sugerencia y aporte como éste son más que bienvenidos :)

Lo más interesante del mail fue conocer algunas de las herramientas que tiene en su sitio mcdlr.com:

CSS Inject

Si vos decís onda “hhmm no estoy seguro” podes probar el código onsite usando http://mcdlr.com/css-inject/ , ves los cambios sin tener que modificar nada realmente.

Esto fue lo que hice para mirar cómo quedaba el código. CSS Inject es una herramienta que nos permite ingresar CSS y generar un bookmarklet. Ese bookmarklet lo podemos usar en cualquier página para aplicar los estilos que escribimos previamente. Me resultó bastante útil.

Dénse una vuelta por ahí, que hay varias herramientas y demos que pueden resultar útiles o simplemente interesantes: Lista de caracteres UTF-8, herramienta para hacer SFW de una imagen NSFW, JS Inject y más con CSS, JavaScript y HTML 5.

» Leer más, comentarios, etc...

MadeInFlex

El Futuro de Adobe Flex

Noviembre 17th, 2011 - [Enlace local]

Los últimos días han sido de especial movimiento en lo que respecta a Adobe por su cambio de dirección con respecto a Flash en los navegadores móviles, los despidos masivos y finalmente el futuro de Flex.

Os dejo una reflexión sobre el análisis de todos los cambios que están ocurriendo.

» Leer más, comentarios, etc...

Koalite's blog

Tutorial node.js + express + jquery (IV): Conclusiones y próximos pasos

Noviembre 17th, 2011 - [Enlace local]

Este post forma parte de una serie de varios:

En este último post de la serie quiero hacer un pequeño resumen de lo que hemos hecho y también de algunas cosas que NO hemos hecho y sería bueno hacer o, al menos, investigar un poco.

Lo que ya sabemos

Está claro que la aplicación de ejemplo era una chorrada, pero aun así nos ha permitido poner en práctica bastantes conceptos útiles a la hora de desarrollar una aplicación con node.js y jQuery. Con lo que hemos visto, podemos:

No está mal. Estos bloques cubren bastantes de las cosas que son necesarias para hacer una aplicación web “moderna”. Sin embargo, hay muchas cosas que se han quedado por el camino.

Lo que podemos mejorar

Entre las cosas que no hemos tratado, hay algunas que me parecen especialmente importantes:

En definitiva, si te ha parecido interesante el tutorial y quieres jugar más con node.js y jquery, creo que han quedado en el aire suficientes cosas como para pasar un rato entretenido. Es posible que en el futuro hable sobre alguna de ellas, así que si te interesa, ya sabes, suscríbete a este blog :-)

Compartir enlace:
Facebook Twitter Email

» Leer más, comentarios, etc...

Ingenieria de Software / Software Engineering / Project Management / Business Process Management

eBook de Silverlight

Noviembre 16th, 2011 - [Enlace local]

Desde la página de Jorge Serrano me entero de la la descarga gratuita del eBook de Silverlight

http://geeks.ms/blogs/jorge/archive/2011/10/22/ebook-gratis-silverlight-for-windows-phone-toolkit-in-depth.aspx

» Leer más, comentarios, etc...

carlosrovira.com

Adobe y el futuro de Flex

Noviembre 16th, 2011 - [Enlace local]

Los últimos días han sido de especial movimiento en lo que respecta a Adobe por su cambio de dirección con respecto a Flash en los navegadores móviles, los despidos masivos y finalmente el futuro de Flex. A continuación quiero ofreceros mi punto de vista como profesional de sector con un profundo conocimiento de la tecnología y relación interna con Adobe.

Flash en el móvil

Con respecto a la primera decisión, no me extenderé mucho. Me parece una buena decisión teniendo en cuenta como está evolucionando el mundo y como se consume contenido en los dispositivos móviles, donde el público prefiere aplicaciones nativas y el navegador tiene el uso para el que fue creado (búsquedas, consumo de información textual, blogs…).

Salvo por la mala comunicación de Adobe PR (Public Relations), Hasta aquí todo correcto. De hecho no creo que esta decisión afectase a nadie ya que con la negativa de Apple de incorporar Flash Player en iOS, la única opción real en los navegadores moviles era HTML5. Esto dejaba las webs informativas tradicionales, blogs y demás sucedáneos, en un formato diseñado con el objetivo de servir información textual. Quizá solo podamos tener un cierto sentimiento de “estar siendo manejados” al quitarnos la libertad de elegir si queremos usar una u otra tecnología o la combinación de ambas.

Para la aplicaciones nativas siempre podemos recurrir a Adobe AIR (que incluye el Flash Player) donde podemos, con un solo desarrollo, desplegar en iOS, Android y BlackBerry. En este sentido los desarrollos Flash y Flex cobran todo su sentido.

El futuro de Flex

Por el contrario el cambio de estrategia con Flex y su malísima comunicación por parte del departamento de relaciones públicas de Adobe (que parece un grupo de aficionados por sus repetidas meteduras de pata), unido al cambio radical de la dirección empresarial de Adobe han provocado que la comunidad Adobe se sienta engañada y enfadada. Engañada por que esto significa un cambio de 180º en la visión marcada por Adobe (Visión que ha sido soportado por millones de profesionales del sector y refrendada por los clientes de dichos profesionales que han confiado en las soluciones tecnológicas soportadas por el fabricante) y enfadados por que la imagen y el daño generado suponen un perjuicio, quedando en el campo de los profesionales el dar explicaciones a los clientes y convencer sobre el uso correcto de Flash/Flex.

Tal es el daño generado por Adobe que desde hace varios días se pide la dimisión de su CEO (537 firmas recogidas en el momento de escribir esta entrada), cuya falta de liderazgo ha llevado a Adobe a ser un actor pasivo en esta guerra tecnológica. Desde que Steve Jobs inició su batalla contra Flash, debido a sus rencillas con Adobe y a su interés de mantener el control del canal de venta dentro de sus dispositivos iOS, Adobe no ha sido capaz de responder a las difamaciones sobre su tecnología, ni de hacer notar las maravillas de la misma al público, lo que finalmente ha llevado a esta situación.

Durante estos años tanto las empresas cliente como los profesionales de la industria han invertido mucho en Flex ofreciendo resultados espectaculares. Esta decisión repentina de Adobe tendría sentido en el caso de que tuviésemos un reemplazo actual para Flex a día de hoy y no solo una promesa de futuro. El segmento de las *aplicaciones* empresariales no es el mismo que el de las *webs* donde HTML5 cobra todo el sentido. HTML5 *no* está todavía preparado para solventar los problemas que surgen en el mundo de las aplicaciones empresariales y lo peor es que no sabemos cuando ni como estará.

Realmente HTML no ha cambiado significativamente durante los últimos años. El motivo por el que todos nos pasamos a Flex fue debido a la fragmentación de los navegadores y a la inconsistencia de la experiencia de usuario que existía entre ellos. Esto sigue siendo así y continuará así a no ser que todos los fabricantes se asocien para crear un motor único que permita asegurar esa experiencia única de visualización.

La innovación generada en el Flash Player a través de los años así como su alta penetración (mayor al 98%) en la base de ordenadores en todo el mundo y su consistencia a través de plataformas convierten a Flash en un entorno de ejecución perfecto y clave en el desarrollo de aplicaciones empresariales.

Además, la naturaleza de la tecnología es lo esperado por un desarrollador de aplicaciones : Lenguaje OOP, debugger, compilación sobre interpretación, IoC, Metadatos, AOP, protocolos de comunicación avanzados como AMF y RTMP, Profiling, Acceso a bajo nivel (Bitearray, pixel level handling), etc…

Estas características son el principal motivo por el que HTML5 no podrá sustituir a Flash (y sobre todo a Flex) en el desarrollo de aplicaciones corporativas. HTML siempre ha sido una tecnología orientada al *documento* y flash orientada las *aplicaciones*. Los desarrollos empresariales (ERPs, sistemas de información corporativos, …) son soluciones de miles/millones de lineas de código que no pueden estar basados en una amalgama desordenada de scripts. El desarrollo y posterior mantenimiento de esas aplicaciones sería muy costoso y en muchos casos imposible de llevar a cabo. La orientación a objetos es crucial en este campo.

¿Que podemos esperar en un futuro de HTML5 y de Flex?

Está claro que si Google, Apple, Adobe y otras muchas están apostando por HTML5 en un futuro será la tecnología predominante. Pero ese futuro no será real hasta dentro de al menos 4 o 5 años. En mi opinión muchos de los problemas que existían en Flash debido a malos programadores los veremos nuevamente en HTML5 ya que no es un problema de la tecnología y si de hacer un buen uso de las mismas.

Por el contrario Flex es la opción real hoy en día para aplicaciones empresariales de cierta envergadura. Como Adobe dice en su última entrada: Nada ha cambiado de un día a otro en el estado de HTML5 y la realidad es que entrar hoy en día en HTML5 supone un alto coste, una alta incertidumbre y estar dispuesto a sufrir los problemas de una tecnología que, lejos de estar madura no soporta la mayoría de las necesidades que actualmente ya están resueltas en Flex.

Además, y según noticias de última hora, Adobe donará Flex a la fundación Apache, donde residen la mayoría de proyectos open source más importantes de los últimos tiempos (Apache Tomcat, Apache Maven, Apache Web Server,…). Esta noticia es muy positiva, ya que el nuevo empuje de la tecnología será llevado por personas con un entendimiento de los problemas mucho más acertado, en mi opinión, que la propia Adobe, cuya filosofía era por naturaleza distinta y más centrada en la venta de “cajas” y herramientas para la edición de contenido.

Además Adobe asegura que el Flash Player continuará soportando las aplicaciones Flex y que Flash Builder esté actualizado con los cambios en el SDK bajo el gobierno de la fundación.

Asi mismo un equipo de ingenieros de Adobe estará asignado a tiempo completo a seguir mejorando Flex que continuará con la evolución marcada para la siguiente release.

En resumen

Realmente nada cambia por el momento. Yo diría que incluso hay mejoras gracias a que Apache formará parte fundamental de la evolución de Flex. Todos los que estamos ahora en Flex tendremos la oportunidad de ver como evoluciona la tecnología (tanto Flex como HTML5) y podremos ir girando progresivamente con las mismas según nuestros intereses. Es de esperar que en el futuro todas las empresas que están empujando el carro de HTML5 lo hagan viable, no solo para moviles o para webs, si no que también consigamos herramientas y mejoras del lenguaje (alguna plataforma OOP sobre la que desarrollar), de forma que HTML5 sea viable para aplicaciones empresariales.

Por el momento HTML5 NO es una opción si tú segmento es el de las aplicaciones empresariales. No lo es hoy y no lo será por los próximos 3 o 4 años. Mientras tanto y durante ese tiempo la mejor opción que tienes es Flex.

Ya tendremos tiempo de ver si HTML5 realmente funciona y consigue evolucionar hacia algo realmente interesante…y si por descontado, los coches eléctricos terminan siendo una realidad ;)

» Leer más, comentarios, etc...

Picando Código

RubyConf Uruguay 2011 – primera jornada parte 1

Noviembre 16th, 2011 - [Enlace local]

RubyConf Uruguay 2011

RubyConf Uruguay 2011

Al igual que la RubyConf Uruguay del año pasado, me traje mucho material para procesar de esta nueva edición, que iré publicando en sucesivas entradas. Pueden encontrar las grabaciones de las presentaciones en Eventials: RubyConfUY. En este primer post les comento algunas de las primeras charlas con Ruby, Rails, Git, y HTML y CSS.

Mi memoria me traiciona, y no me acuerdo el nombre… Pero el evento comenzó con un programador que presentó Pair Programming. Habló algo de la técnica e invitó a los asistentes a una estación de Pair Programming armada afuera del auditorio para tener sesiones de pares en los recesos. Hubo mucha gente que pasó por ahí, así que bueno, con suerte se ha difundido un poco más la cultura de esta técnica.

¿Qué es tan especial de Ruby On Rails?

Stephen AndersonLa primera charla ¿Qué es tan especial de Ruby On Rails? estuvo a cargo de Stephen Anderson (@bendycode). Stephen es un maestro y mentor de Ruby y Rails. Enseña Rails en Madison College y es fundador de Bendyworks. Algo a destacar es que Stephen dió su charla completamente en español. Un muy buen español hay que decirlo.

Su charla consistió en una introducción al lenguaje Ruby y al framework Rails. Habló de las características y ventajas de Ruby. Cuando habló de Rails mostró una imagen que generó algo de controversia, sobre todo para cierto troll que hubo durante la conferencia que le cayó bastante mal:

Java Vs. Ruby

Java Vs. Ruby

Pueden ver la grabación en Eventials (tiene algunos problemas de audio, pero se puede ver), o descargar el PDF de su presentación.

Ruby On Rails

Santiago PastorinoLa siguiente charla: Ruby On Rails por la gente de WyeWorks. Estuvo a cargo de Santiago Pastorino (@spastorino) – Rails Core Developer y Jorge Bejar (@jbejar) – Ingeniero de Software.

La presentación sirvió como introducción para aquellos que no conocieran Rails y mostraron qué cosas se puede hacer con esta herramienta, y lo rápido que se pueden obtener resultados. Basados en algunos Screencasts de Rails, crearon un Blog en menos de una hora.

Jorge BejarUna herramienta muy útil que mencionaron durante la presentación fue The Ruby Toolbox, un catálogo de plug-ins, gemas, herramientas y recursos para Ruby y Rails. Lo interesante del sitio es que se basa en las descargas y estadísticas de Github para definir la popularidad de cada elemento. Están todos separados por categoría por lo que es el lugar ideal para encontrar una herramienta cuando no sabemos cuál usar. Me la habían recomendado hace un tiempo por Twitter, y estoy casi seguro que fue alguien de WyeWorks mismo.

El código fuente del blog lo pueden encontrar en github. La presentación en Eventials acá.

Santiago mencionó al final de la charla que WyeWorks está contratando, así que los interesados pueden enviar un mail a jobs en wyeworks.com.

Un Cuento de Tres Árboles

Scott ChaconEl siguiente orador fue Scott Chacon (@chacon), CIO de Github, autor del libro Pro Git, Git Internals PDF, el sitio git-scm.com y el Git Community Book. El año pasado ya habíamos tenido el gusto de presenciar una charla de Scott Chacon (Segunda jornada RubyConf Uruguay 2010). Antes de comentarles sobre la charla de Scott, recomendarles que si no usan Git, deberían. Y como se dijo en la conferencia -creo que fue foca- si no usan GitHub, deberían hacerlo también.

Yendo a la charla, esta vez presentó Un cuento de tres árboles, una presentación que se enfoca en el comando git reset. Destacar también que este año Scott también dió su charla completamente en español. Para explicar git reset, Scott piensa en Git como un administrador de tres árboles:

Con el comando git reset podemos deshacer commits, y sacar archivos del staging area. La charla estuvo muy interesante, estuve probando en mi laptop con algún repo git a medida que Scott iba explicando. Fue bastante didáctica aunque creo que costó más entenderle en español, pero hay que reconocer que tiene un valor muy grande que el autor haya decidido dar la charla en español. Al finalizar su ponencia, Scott le presentó un certificado al público asistente:

Git Reset Training

Git Reset Training

Pueden ver la grabación en Eventials, descargar la presentación en formato .key, y leer más información al respecto en esta entrada del blog del libro Pro Git: Reset Demystified.

HTML & CSS – Best Practices

Verónica RebagliatteLa siguiente charla estuvo a cargo de Verónica Rebagliatte (@rebagliatte), diseñadora UI y desarrolladora. Su trabajo puede apreciarse en http://rebagliatte.com.

Verónica habló de semántica, y qué hacer para que el código sea más entendible, así como las prácticas para mantener la semántica. El segundo punto que cubrió fue la performance (o rendimiento), atacándola desde tres puntos: JavaScript, CSS y contenidos. Más adelante habló de mantenibilidad, como para mantener un buen karma y ser buen compañero, y lo definió con una frase que vale la pena reproducir:

Que no te corran los fantasmas de las chanchadas pasadas.

Como “bonus track” habló de cómo elegir el mejor layout en una aplicación según el viewport. Pueden encontrar la grabación y la presentación dinámica en Prezi.

Conclusión

Bueno, esto fue apenas una parte de las presentaciones de la primer jornada de RubyConf Uruguay. Como verán, hubieron temas variados y sumamente interesantes. Lo voy dejando por acá para no hacer demasiado largo el post, pero estén atentos a futuras entregas en estos días.

» Leer más, comentarios, etc...

Escuela De Codigo

Subir imágenes automáticamente a WordPress después de hacer el screenshot

Noviembre 16th, 2011 - [Enlace local]

Generalmente cuando hago un articulo tipo “¿Como hacer  x cosa?” o un tutorial mas o menos extenso, se requieren muchas capturas de pantalla para ir mostrando al lector el proceso de una manera visual mucho mas atractivo de lo que es solo un listado de pasos y cada una de esas imágenes me toca subirlas a la librería multimedia de WordPress, lo cual para mi es: aburrido y repetitivo. Se que WordPress cuenta con un uploader de imágenes que me permite subir mas de una a la vez y que WordPress 3.3 implementa un uploader del tipo “Drag and Drop” pero, y si yo quisiera que luego de tomar el screenshot que mi imagen recien creada se suba automáticamente a mi blog sin ninguna intervención de mi parte…¿¿como lo hago??? la respuesta a continuación.

¿Que vamos a necesitar?

Paso 0: Conocer Ruby

Ruby es un gran lenguaje no debes de evitar conocerlo a profundidad pero, para este articulo bastara con que sepas lo siguiente:

Paso 1: Hacer login en WordPress

WordPress no permite subir imágenes ni archivos a cualquier desconocido, asi que el primer paso es propocionarle a nuestro script las credenciales de acceso para que se conecte por nosotros.

agent = Mechanize.new
 
page = agent.post("http://www.tudominio.com/wp-login.php", {
"log" => "tu_usuario",
"pwd" => "tu_password",
"wp-submit" => "Log In",
"redirect_to" => "http://www.tudominio.com//wp-admin/",
"testcookie" => "1"
})

Inmediatamente después corroboramos que nuestro login fue ejecutado exitosamente

text = page.search(%Q{//div[@id='login_error']}).text
if text.empty?
#login correcto
end

Paso 2: Obtener un wpnonce valido

WordPress utiliza un valor llamado wpnonce por cuestiones de seguridad, así que el siguiente paso es obtener este valor (que necesitaremos para enviar las imagenes)

page = agent.get("http://www.tudominio.com/wp-admin/media-upload.php")
@_wpnonce = page.forms.first._wpnonce

Paso 3: Recorrer los archivos a enviar

Para este script definiremos un directorio donde pondremos nuestras imágenes  y recorreremos todos los archivos que contenga para que sean subidas a nuestro blog

Dir.foreach("#{dir}/") { |file|
str = "#{dir}/"+file
if File.file?(str)
File.open(str) do|message|
#Aqui enviaremos el contenido de este archivo
end
end
end

Paso 4: Subiendo imagenes!!

Y la parte principal: subir las imagenes. Es posible con estas pocas lineas de código

page = agent.post("http://www.tudominio.com/wp-admin/media-upload.php", {
"inline" => "",
"upload-page-form" => "",
"_wpnonce" => @_wpnonce,
"post_id" => "0",
"html-upload" => "Upload",
"async-upload" => message
})

El script final tendría que verse algo así:

require 'rubygems'
require 'mechanize'
agent = Mechanize.new
 
page = agent.post("http://www.tudominio.com/wp-login.php", {
"log" => "tu_usuario",
"pwd" => "tu_password",
"wp-submit" => "Log In",
"redirect_to" => "http://www.tudominio.com/wp-admin/",
"testcookie" => "1"
})
 
text = page.search(%Q{//div[@id='login_error']}).text
 
if text.empty?
page = agent.get("http://www.tudominio.com/wp-admin/media-upload.php")
@_wpnonce = page.forms.first._wpnonce
 
Dir.foreach("/home/user/imagenes/") { |file|
str = "/home/user/imagenes/"+file
if File.file?(str)
File.open(str) do|message|
page = agent.post("http://www.tudominio.com/wp-admin/media-upload.php", {
"inline" => "",
"upload-page-form" => "",
"_wpnonce" => @_wpnonce,
"post_id" => "0",
"html-upload" => "Upload",
"async-upload" => message
})
end
end
}
end

Ahora con tan solo ejecutar ruby wp.rb en alguna terminal, las imágenes contenidas en el directorio elegido se subieran a nuestro blog.

Oye eso no es automático!!

No desesperes que aun no hemos terminado

Paso 5: Creando servicio

Para lograr que nuestro script se encargue automáticamente de subir las imágenes, necesitamos que corra como daemon o servicio, es decir en segundo plano (para que nos despreocupemos de estarlo ejecutando) cada cierto tiempo para que de esta forma sea el programa quien lea el directorio que le indiquemos y si encuentra algo que subir lo haga.

Utilizaremos la gema forever para conseguir esta funcionalidad, el script modificado queda así:

require 'rubygems'
require 'forever'
require 'mechanize'
Forever.run do
every 60.seconds do
agent = Mechanize.new
 
page = agent.post("http://www.tudominio.com/wp-login.php", {
"log" => "tu_usuario",
"pwd" => "tu_password",
"wp-submit" => "Log In",
"redirect_to" => "http://www.tudominio.com/wp-admin/",
"testcookie" => "1"
})
 
text = page.search(%Q{//div[@id='login_error']}).text
 
if text.empty?
page = agent.get("http://www.tudominio.com/wp-admin/media-upload.php")
@_wpnonce = page.forms.first._wpnonce
 
Dir.foreach("/home/user/imagenes/") { |file|
str = "/home/user/imagenes/"+file
if File.file?(str)
File.open(str) do|message|
page = agent.post("http://www.tudominio.com/wp-admin/media-upload.php", {
"inline" => "",
"upload-page-form" => "",
"_wpnonce" => @_wpnonce,
"post_id" => "0",
"html-upload" => "Upload",
"async-upload" => message
})
end
end
}
end
end
end

Ahora tu script es un servicio por lo que puedes ejecutar

ruby wp.rb start

e inicializarlo, de igual manera puedes detenerlo pasandole como argumeto stop

Paso 6: Puliendo un poco

Y ya para terminar haremos unos pequeños ajustes, un poco de refactoring de código para mejorar el rendimiento de la mini aplicación. Verificaremos si existen archivos para enviar , no tiene caso loguearnos e intentar enviar algo cuando no hay nada y una vez hemos enviado el archivo lo moveremos a otra carpeta para evitar subir el mismo archivo una y otra vez.

require 'rubygems'
require 'forever'
require 'mechanize'
Forever.run do
every 60.seconds do
agent = Mechanize.new
 
if Dir.glob("/home/user/imagenes/*.*").length > 0
page = agent.post("http://www.tudominio.com/wp-login.php", {
"log" => "tu_usuario",
"pwd" => "tu_password",
"wp-submit" => "Log In",
"redirect_to" => "http://www.tudominio.com/wp-admin/",
"testcookie" => "1"
})
 
text = page.search(%Q{//div[@id='login_error']}).text
 
if text.empty?
page = agent.get("http://www.tudominio.com/wp-admin/media-upload.php")
@_wpnonce = page.forms.first._wpnonce
 
Dir.foreach("/home/user/imagenes/") { |file|
str = "/home/user/imagenes/"+file
if File.file?(str)
File.open(str) do|message|
page = agent.post("http://www.tudominio.com/wp-admin/media-upload.php", {
"inline" => "",
"upload-page-form" => "",
"_wpnonce" => @_wpnonce,
"post_id" => "0",
"html-upload" => "Upload",
"async-upload" => message
})
if !File.exist?("/home/user/imagenes/_bpk")
FileUtils.mkdir "/home/user/imagenes/_bpk"
end
FileUtils.mv(str, "/home/user/imagenes/_bpk/"+file,:force => true)
end
end
}
end
end
end
end

Extra: Regalo para los que tienen prisa!

Si veniste aqui pensando que seria una tarea fácil, no te has equivocado, crear este script no te llevara ni 15 minutos pero, si no dispones de tanto tiempo, basado en este código cree una gema que simplifica aun mas todo el proceso

wpuploader-0.0.1.gem

Instala

gem install wpuploader-0.0.1.gem

Y ejecuta

wpuploader start

Completa los datos que se te pidan y despreocupate de tener que subir las imágenes a tu blog. En tu carpeta de usuario se creara el directorio .wpuploader y dentro de el veras un archivo de configuración… y lo que queda solo es disfrutar :)

Lectura Obligatoria

» Leer más, comentarios, etc...

Picando Código

Datos Abiertos: Qué son y por qué debería importarte

Noviembre 15th, 2011 - [Enlace local]

Datos abiertos

Datos abiertos

Ayer lunes se realizaron un par de conferencias sobre Datos Abiertos en el Museo Nacional de Artes Visuales. Empezaba a las 18, así que salí lo mas rápido posible de la oficina, tomé el ómnibus y llegué al museo a poco de haber comenzado la primer charla. Más adelante actualizaré el post con más información que no tengo a mano en este momento (enlaces a las presentaciones y demás).

¿Qué son datos abiertos? De WikiPedia:
Datos abiertos (open data en inglés) es una filosofía y práctica que persigue que determinados datos estén disponibles de forma libre a todo el mundo, sin restricciones de copyright, patentes u otros mecanismos de control. Tiene una ética similar a otros movimientos y comunidades abiertos como el código abierto (open source en inglés) y el acceso libre (open access en inglés).

Pues bien, la primer charla de la conferencia estuvo a cargo de la Intendencia de Montevideo. El funcionario contó un poco cómo la Intendencia llegó a la política actual de datos abiertos.

¿Bajo qué condiciones se liberan estos datos?

La Intendencia de Montevideo cree que los datos públicos deben ser abiertos tal como manifiesta la resolución 640/10. Por eso se adhiere a los 8 principios de datos abiertos en el gobierno y está progresando en publicar la información que se genera para que pueda ser utilizada por quien la necesite, para lo que la necesite.

Para que esto sea posible, se debe asegurar que los datos sean efectivamente públicos (es decir, no tengan el estatus de reservados, confidenciales, sensibles o secretos, según lo definen las leyes Nº 18.381 y 18.331). Asimismo, los datos deberán estar verificados y respaldados por una dependencia  responsable dentro de la Intendencia de Montevideo, e indicar claramente cuál es su fecha de vigencia.

¿De qué tipo de datos estamos hablando?

Recientemente se anunció la noticia (tuvo bastante prensa) de que la Intendencia liberó la Ejecución del presupuesto en el período de 2005 a 2010. Esto es en gastos de funcionamiento, inversiones, retribuciones personales e ingresos. También se cuenta con los horarios de ómnibus urbanos, con código de punto de control, las líneas de ómnibus, y mucha información geográfica de Montevideo.

Esta información ya está siendo utilizada en aplicaciones como Cómo ir, un servicio que permite obtener rutas en ómnibus o a pié entre dos puntos de la ciudad. También una aplicación para consultar los horarios de ómnibus. OpenStreetMap se nutrió de la información geográfica liberada por la Intendencia de Montevideo y así más.

Datos abiertos - IM

Datos abiertos - IM

La Intendencia de Montevideo está apostando a una comunidad colaborativa, adoptando un modelo abierto y cooperativo para hacer un uso eficiente de esta información. Por eso están alentando a los ciudadanos a hacer uso de estos datos.

Es así que incluyen en la página web de datos abiertos formularios para que los usuarios sugieran nuevos datos para publicar, correcciones, compartir ideas y registrar aplicaciones. Además es responsabilidad de los ciudadanos de generar las herramientas para parsear esa información y presentarla de una manera que sea útil.

La segunda charla estuvo a cargo de Evan “rabble” Henshaw, y ahondó más en qué son los datos abiertos en sí, y cómo se están usando en otras partes del mundo.

Si bien la liberación de los datos es una parte importante, desde “abajo” hay que darle un uso. Uruguay es uno de los países más evolucionados en lo que respecta a políticas de datos abiertos en el gobierno y la comunidad tiene que ser conciente de los datos a los que puede acceder y buscar la manera de usarlos.

Evan comentaba como en muchos países existen grupos activistas exigiéndole a sus gobiernos los datos abiertos que nosotros tenemos a disposición. Así que hay que valorar y hacer uso de la información que tenemos a disposición, y seguir exigiendo más datos abiertos de los distintos entes.

En la presentación Evan mostró parte de la evolución de OpenStreetMap y cómo con ayuda de distintas comunidades y voluntarios ha ido creciendo exponencialmente con el tiempo. En algunas zonas ha superado la información de Google Maps, la plataforma con la misma funcionalidad pero de carácter cerrado. Además, se comentaron varios sitios en distintas partes del mundo donde se hace uso de la información que liberan los gobiernos para el bien de los ciudadanos.

Datos Abiertos - rabble

Datos Abiertos - rabble

A pesar de la poca convocatoria, hubo un intercambio realmente interesante entre los asistentes y los oradores, aportando ideas muy concretas y haciendo preguntas. Cuanto más personas se involucren en este tipo de iniciativas, mejor para todos.

Esto es solo una parte de una campaña mucho más grande donde también está participando AGESIC “Agencia para el Desarrollo del Gobierno de Gestión Electrónica y la Sociedad de la Información y del Conocimiento”. Es un organismo que depende de la Presidencia de la República (unidad ejecutora 010 dentro del inciso 02). Funciona con autonomía técnica. Tiene como objetivo procurar la mejora de los servicios al ciudadano, utilizando las posibilidades que brindan las Tecnologías de la Información y las Comunicaciones (TIC).

Sinceramente me decepciona ver tan poca gente en eventos de este tipo. En este caso se le puede atribuir a la poca publicidad del evento, pero creo que es necesario que la gente en general esté al tanto de la importancia y el valor de estas campañas de datos abiertos y participemos. Hay que generar una cultura con esta mentalidad y tratar de difundir estas ideas, el conocimiento y que todos podamos aprovecharlo.

Si aún siguen leyendo es que les interesa el tema, por lo que les recomiendo leer la página web sobre datos abiertos de AGESIC. Ahí se explica un poco más la utilidad y objetivos de los datos abiertos y se cuentan algunos ejemplos de aplicaciones que hacen uso de datos abiertos por el bien común.

Desarrollando América Latina

Desarrollando América Latina

Desarrollando América Latina

Para cerrar la charla, Evan presentó el concurso Desarrollando América Latina en Uruguay. Se trata de un concurso donde participarán 6 países del continente para encontrar soluciones digitales a problemas sociales. En este primer encuentro, los participantes trabajarán con tres temas: educación, presupuesto público y seguridad. Los objetivos son bastante interesantes, y ojalá logremos todos con este evento:

Además de los objetivos planteados, el concurso cuenta con muchos premios, además de la satisfacción de contribuir a la sociedad con código, ideas o diseños que ayuden a aprovechar estos datos y resuelvan alguno de los problemas mencionados.

Los invito a inscribirse en este enlace.

Para finalizar, los dejo con una frase del sitio de AGESIC:

Aún es difícil dimensionar el impacto de esta nueva tendencia. Existen numerosos casos en que los Datos Abiertos han generado diversos valores sociales y económicos. Nuevas combinaciones de datos pueden crear nuevos conocimientos y nuevas ideas que inspiran, a su vez,  a crear nuevos campos de aplicación.

Más información:

» Leer más, comentarios, etc...

Variable not found

Limpiar un input type=file

Noviembre 15th, 2011 - [Enlace local]

No es algo excesivamente frecuente, pero en ocasiones podemos necesitar limpiar el valor de un campo de tipo file (el que usamos para hacer los uploads) de un formulario, por ejemplo, para evitar que el usuario envíe un archivo que por cualquier motivo no deba ser subido al servidor.



O dicho de otra forma, imaginemos la siguiente porción de un formulario en pantalla, que podría ser generada con el código que podéis ver justo a continuación:

Campo de envío de archivos

<label for="archivo">Archivo a enviar:</label>
<input type="file" id="archivo" name="archivo" />
<input type="button" onclick="limpiarInputFile('archivo');" value="Limpiar" />


Y la pregunta en este momento sería, ¿qué código deberíamos implementar en la función limpiarInputFile() que estamos utilizando en el evento onclick si quisiéramos limpiar o inicializar el contenido del campo archivo?



Aunque de forma intuitiva podría parecer que basta con establecer el valor del campo a una cadena vacía, una prueba rápida nos demostrará que esto no es posible. Desde hace ya tiempo, por motivos de seguridad, los navegadores no permiten el acceso de escritura a la propiedad value en los campos de envío de archivos, por lo que nos encontramos una vía sin salida. Esto lo vemos con el siguiente código, utilizando jQuery:



    function limpiarInputfile(id) {
        var input = $('#' + id);
        var nuevoValor = "c:\\windows\\system32\\mspaint.exe";
        
        alert(input.val());       // Muestra "C:\Datos.dat"
        input.val(nuevoValor);    // Establecemos un nuevo valor
        alert(input.val());       // ¡¡Muestra "C:\Datos.dat"!!
    }


Como vemos, somos vilmente ignorados cuando intentamos establecerle un valor.



Pues bien, una posible solución consiste en eliminar del DOM el elemento <input type="file"> y volver a crearlo justo después en el mismo lugar. He visto por ahí varias implementaciones que obligaban a introducir este elemento dentro de un contenedor, pero he creado otra que creo que es más sencilla e igual de efectiva:



    function limpiarInputfile(id) {
        var input = $('#' + id);
        var clon = input.clone();  // Creamos un clon del elemento original
        input.replaceWith(clon);   // Y sustituimos el original por el clon
    }


Y eso es todo :-). Observad que lo único que hacemos es crean un clon del elemento original cuyo value por supuesto estará en blanco (recordad que esta propiedad no se puede establecer), y justo a continuación eliminamos el elemento original sustituyéndolo por este clon.



Si queremos generalizar este código e implementar esta funcionalidad de forma no intrusiva podríamos hacer lo siguiente:



    $(function () {
        $("input[type=file]").after(
            "<input type='button' class='limpiar-inputfile' value='Limpiar'>"
        );
        $(".limpiar-inputfile").click(function () {
            var input = $(this).prev("input[type=file]");
            var clon = input.clone();
            input.replaceWith(clon);
            return false;
        });
    });


Este código añade automáticamente un botón “Limpiar” a continuación de todos los <input type=file> de la página, implementando en el manejador del evento click la lógica de inicialización del componente que hemos visto antes. De esta forma, sólo se introducirá en la página el botón de limpiado cuando estén activados los scripts, que es en el único momento en que su ejecución tendrá sentido con la solución propuesta.



Espero que os sea de utilidad.



Publicado en: Variable not found.



» Leer más, comentarios, etc...

Picando Código

RubyConf Uruguay 2011

Noviembre 14th, 2011 - [Enlace local]

RubyConf Uruguay 2011

RubyConf Uruguay 2011

Pasó otra edición de RubyConf Uruguay, y terminó la gira Ruby Sur 2011. Se mantuvo el nivel de excelencia del año pasado, y me traje montones de ideas para procesar, conocimientos nuevos, tecnologías y herramientas para estudiar e investigar, nuevos amigos y más.

Además de la conferencia, Heroku y Github nos ofrecieron dos noches de tragos gratis. Ambos drink-ups sirvieron como instancia de socialización entre los asistentes y oradores, y llevó a charlas  muy interesantes, nuevas amistades e ideas para compartir.

Esta semana iré procesandola información y armando los posts correspondientes :)

Desde acá mis felicitaciones a todo el equipo de la organización por el excelente trabajo para sacar adelante la conferencia. También agradecerles por jugarse a organizar una conferencia de este nivel en nuestro país. Gracias a todos los oradores por haber participado -algunos desde muy lejos-, y presentar las charlas excepcionales que hubieron. Un esfuerzo muy grande imagino por toda la comunidad latinoamericana de Rubistas, va desde acá mi reconocimiento.

Les dejo links a algunas fotos del evento:

También la URL del sitio en Eventials, donde hay charlas con video y presentaciones http://www.eventials.com/rubyconfuy

Quedé muy motivado y con ganas de investigar y aprender mucho. Espero poder abarcar todo en algunos posts, intentaré tener todo arriba esta semana. Mucho para pensar y procesar, pero muy contento con todo lo que me aportó la conferencia. Espero con ansias la edición 2012, y quedo con ganas de visitar las ediciones de Argentina y Chile el año que viene…

http://www.eventials.com/rubyconfuy

» Leer más, comentarios, etc...

Variable not found

De vuelta del CommunityDay y enlaces interesantes 59

Noviembre 14th, 2011 - [Enlace local]

FuengirolaPues ya estamos de vuelta del evento que tanto tiempo llevábamos esperando: el Community Day 2011. Un día en Fuengirola (Málaga) repleto de sesiones interesantes, mucho tiempo para desvirtualizar compañeros a los que seguimos desde hace tiempo, y en todo momento disfrutando de la compañía de auténticos fenómenos a los que algunos sólo podemos ver en ocasiones señaladas como esta.



Desde aquí, dar la gracias a la organización y a todos los asistentes que han vuelto a conseguir que este evento sea una experiencia inolvidable.



Y para volver poco a poco a la normalidad, estos son los enlaces publicados en Variable not found en Facebook y Twitter del 7 al 10 de noviembre de 2011. Quizás poquitos en comparación con otras veces, pero espero que os resulten igualmente interesantes. :-)

Y no olvidéis que podéis seguir esta información en vivo y en directo desde Variable not found en Facebook, o a través de Twitter.



Publicado en: Variable not found



» Leer más, comentarios, etc...

Koalite's blog

Cuánto daño ha hecho… IValidable (y sucedáneos)

Noviembre 14th, 2011 - [Enlace local]

Hay ideas que aparecen la mejor de las intenciones, que son útiles, incluso muy útiles, pero que llega un momento en que su intención original se pierde, su objetivo se diluye y su uso se deforma hasta que se convierten en malas ideas.

Ya he hablado de algunas de ellas, como el mal uso que se da ServiceLocator, pero hoy me quiero centrar en el interface IValidable. Este interface se presenta de varias formas y con diversos nombres, como IValidatableObject (muy usado en ASPNET MVC), pero en general es algo así:

public interface IValidable
{
   ValidationResult Validate();
}

public class ValidationResult
{
   private readonly IList messages = new List();

   public void AddError(string property, string message)
   {
       messages.Add(new ValidationMessage(property ,message);
   }

   public bool IsValid
   {
      get { return !messages.Any(); }
   }

   // ...
}

public class ValidationMessage
{
   public string PropertyName { get; private set; }
   public string ErrorMessage { get; private set; }

   public ValidationMessage(string propertyName, string errorMessage)
   {
       PropertyName = propertyName;
       ErrorMessage = errorMessage;
   }
}

La idea es simple y parece buena. Tenemos un interface que podemos implementar en aquellas clases que sean susceptibles de ser validadas. De esa forma, podremos invocar el método Validate y obtener el resultado de la validación.

Los casos de aplicación de esta técnica son numerosos y genera un código bastante limpio y manejable en muchos de ellos. Por ejemplo, mezclado con DataBinding y unos atributos de validación ([Required], [MinLength(17)], etc.) que se validan directamente desde una clase base, acaba por crear una estructura bastante apañada para lidiar con la validación en la capa de interfaz de usuario.

Esto funciona bien siempre que la clase que implementa IValidable sea una clase que esté muy restringida a un ámbito y una operación muy concretos dentro de nuestra aplicación, como puede ser un ViewModel.

También puede funcionar en aplicaciones muy simples en las que no hay casi lógica, donde mezclando Active Record y Transaction Script tienes la aplicación hecha.

¿Cuál es el problema?

El problema es que ser válido es una cosa muy relativa. ¿Es válido Sergio Ramos de central? Pues parece ser que sí. ¿Es válido Sergio Ramos como presidente de gobierno? Viendo lo que hay, podría ser. ¿Es válido Sergio Ramos como premio Nobel? Definitivamente, no. Sin embargo, el “objeto” Sergio Ramos siempre es el mismo, lo que cambia… es el contexto.

Al principio, cuando uno piensa en validación, parece que automáticamente piensa en “válido para guardar en la base de datos”, pero en cuanto una aplicación crece, aparecen más casos de validación para una misma clase, cada uno con sus propios requisitos. El interface IValidable obliga a un diseño en que un objeto es responsable de su propia validación, pero no distingue para qué se está realizando esa validación.

Otro problema es que se acaba aplicando el interface IValidable a cosas sin sentido. Me duele especialmente verlo en una entidad (en el sentido DDD) como ocurre en la aplicacón de ejemplo DDD de Microsoft España. Además de lo que acabamos de contar sobre validar para distintos contextos, ¿qué sentido tiene validar una entidad? Una entidad, y más una raíz de agregado como en ese caso, por definición, NO puede estar en un estado inválido, ya que una de sus misiones en esta vida es garantizar que los datos que contiene son coherentes y se cumplen SIEMPRE sus invariantes.

Para evitar el problema de la validación en distintos contextos, Martin Fowler propone tener un método IsValid para cada caso de validación. Por seguir con el ejemplo de Sergio Ramos, tendríamos:

public class Person
{
   public bool IsValidAsCentralDefender();
   public bool IsValidAsPresident();
   public bool IsValidAsNobelPrize();
   ...
}

Pues, aunque lo diga Martin Fowler, a mi no me convence. Creo que es una violación del OCP, del SRP y de no sé cuantas cosas más. La clase validada acaba teniendo distintas responsabilidades relativas a la validación de escenarios que, en principio, no tienen porqué ser importantes para la clase. Además, cada vez que añadimos un nuevo caso de uso, nos obliga a tocar la clase, y eso es, cuanto menos, poco deseable.

La “solución” que suelo aplicar es similar a la de Castle Validator, aunque más simple. En lugar de un interface IValidable, tengo un interface IValidator con este aspecto:

public interface IValidator
{
   ValidationResult Validate(T instance);
}

Así se consigue extraer la lógica de validación de la clase validada, y si hace falta añadir nuevos validadores para nuevos escenarios, no hay problema, se añaden y ya está. El código que ya existía no se toca y, por tanto, no se rompe. Las responsabilidades no se mezclan. Si hace falta reutilizar reglas de validación en distintos contextos, es fácil, se puede invocar un validador desde otro y componer el resultado.

Una ventaja adicional de hacerlo de esta manera es que la validación pasa a ser responsabilidad de servicios, que se crean a través de un contenedor de IoC y, por tanto, pueden recibir dependencias, por ejemplo de un IRepository para validar que el nombre es único antes de intentar guardar en la base de datos.

Quizá te estés preguntando una cosa: si la lógica de validación está en otra clase, ¿cómo puedo validar las propiedades privadas? No puedes, pero es que no hace falta. Las propiedades privadas son privadas por algo. Son un detalle de implementación. Siempre deberían tener valores válidos, puesto que son gestionados por la clase a la que pertecenen.

En definitiva, esto es lo de siempre. No hay una solución que valga para todo, pero sí hay soluciones mejores o peores para ciertos casos. Antes de aplicar ciegamente lo que se ve por ahí (empezando por este mismo blog), es mejor pararse un poco y pensar si realmente tiene sentido.

Compartir enlace:
Facebook Twitter Email

» Leer más, comentarios, etc...

Javier Pérez

Cómo promocionar un blog: Emailing

Noviembre 14th, 2011 - [Enlace local]

Cómo promocionar un blog

ÍNDICE

0. Introducción
1. SEO
2. SEM
3. Social Media
4. Emailing
5. Usabilidad
6. Analítica Web
7. Afiliación

Emailing

Las campañas de emailing pueden servir para dos cosas: para vender y para fidelizar. Dado que nos estamos ciñendo a promocionar blogs, nos vamos a centrar en fidelizar a tus lectores. Se trata de que cuando escribas un nuevo artículo éste le llegue por email a todos y cada uno de tus suscriptores. En estos tiempos de Facebook y demás redes sociales, el email aún sigue siendo el rey de Internet, es la mejor herramienta de comunicación jamás inventada, directa, universal, libre, casi instantánea, reenviable (muy importante), y no intrusiva, es decir, no se obliga al lector a leer al email, él lo lee cuando quiere.

Para hacer esto, tu blog ya debe tener previamente audiencia, ya que necesitas un lector que poder fidelizar mediante emailing. Tendrás que añadir un formulario de alta en un lugar estratégico de la web (ver capítulo de usabilidad de la semana que viene), donde tu lector introduzca al menos su email, aunque es muy recomendable que también introduzca su nombre para poder personalizar los mensajes, importante si queremos afinar nuestra campaña.

Existen muchas herramientas para hacer esto, pero yo te recomiendo dos: Feedburner (la más sencilla y cómoda) y MailChimp (la opción profesional). En WordPress encontrarás plugins para hacer esto (plugin MailChimp).

Feedburner (comprado por Google) fue concebido para ofrecer estadísticas de tu feed, pero ha ido evolucionando hasta ofrecer diversas y útiles herramientas, entre las cuales está la de crear suscripciones por email. Te ofrece un formulario muy sencillo y casi sin ninguna posibilidad de personalización, pero para nuestro propósito es totalmente válido. Como valor añadido te permite añadir tu código AdSense o enlaces para compartir los artículos en las redes sociales.

Con MailChimp podrás añadir más contenidos a esos emails, como destacar un artículo, un página especial que hayas creado, publicitar un libro que has publicado, un sorteo, e incluso poner publicidad (hasta donde yo sé, no permite AdSense). Además, te muestra estadísticas de cada campaña enviada (emails no leidos, leidos, leidos y seguido el enlace). Eso sí, toda esa personalización que ofrece MailChimp conlleva una mayor complejidad, y necesitarás tiempo para hacerte con él.

El valor añadido de MailChimp es que generas tus propias listas de emails, algo que no es posible con Feedburner, que podrás usar para enviar emails promocionales a todos tus seguidores (por ejemplo, informando de un libro que acabas de publicar). Hay que tener mucho cuidado con esto para no incurrir en spam. Si vas a enviar contenidos adicionales a los artículos del blog deberás notificárselo claramente al lector en el formulario de registro.

Otro aspecto muy importante que debes contemplar es la suscripción por email a los comentarios. Normalmente un usuario escribe un comentario en un blog y no vuelve nunca más. Si estuviera suscrito a los comentarios le llegaría un email notificándole cada nuevo comentario, con lo cual es muy posible que vuelva a tu blog para volver comentar.

WordPress ya provee una suscripción por RSS a los comentarios de un artículo (añadiendo /feed/ a la URL), pero crear una entrada en Feedburner por cada artículo para poder mostrar la suscripción por email no es nada cómodo. Así que necesitarás implementar ese código tú mismo, o bien mediante los diversos plugins que existen para hacer esto (ver plugin Subscribe to Comments Reloaded).

Espero que este artículo te haya sido de utilidad. Si necesitas ayuda profesional no dudes en contactar conmigo.

La siguiente semana hablaré de usabilidad.

» Leer más, comentarios, etc...

Escuela De Codigo

Quiero ser desarrollador web, ¿Que debo aprender?

Noviembre 14th, 2011 - [Enlace local]

Desde que se acuño el termino web 2.0 se dio un boom de tener (o intentarlo ) absolutamente todo en la nube (en Internet) y es por eso que hoy en dia prácticamente toda nuestra actividad frente a la computadora, lo que antes podriamos hacer en un escritorio común y corriente, lo podemos hacer solo con un navegador, un sitio web y desde cualquier lugar con conexión.

Gracias a este auge, las aplicaciones de escritorio cada día son menos demandadas y son las aplicaciones web las que han ido tomando su lugar, las empresas ya no necesitan un programador, quieren un desarrollador web; Y así surge la duda de aquellos que toda la vida han programado haciendo aplicaciones para desktop

¿Que lenguajes de programación debo aprender para desarrollar aplicaciones web??

Adaptación o extinción

Si ya te has hecho la pregunta anterior dejame felicitarte porque eres de los que ha tomado conciencia que en la nube esta el futuro no solo de las tecnologías y comunicaciones sino de tu sobrevivencia en el mundo laboral, mas  fácil no puede ser: aprende a crear aplicaciones web o dedicate a otra cosa! Y es una advertencia muy  palpable y real, adaptarse o morir.

Muy bien me has asustado ¿que debo aprender?

Existen una infinidad de lenguajes de programación pero, son pocos los que son un verdadero estándar de la industria y en esos nos concentraremos inicialmente, a continuación un listado de lo que a mi parecer es indispensable que aprendas y manejes como un ninja.

HTML

HTML, siglas de HyperText Markup Language («lenguaje de marcado de hipertexto»), es el lenguaje de marcado predominante para la elaboración de páginas web.

No puedes ser samurai sino sabes manejar la espada, no puedes ser astronauta si le tienes miedo a las alturas,no puedes ser desarrollador web sino conoces HTML, asi de extremo, drastico y sencillo. Quieres crear desde simples sitios web hasta fantásticas aplicaciones de ultima generacion, empieza por aprender HTML y aprenderlo muy bien porque es la base de todo.

JAVASCRIPT

JavaScript es un lenguaje de programación interpretado, dialecto del estándar ECMAScript. Se define como orientado a objetos,basado en prototipos, imperativo, débilmente tipado y dinámico. Se utiliza principalmente en su forma del lado del cliente (client-side), implementado como parte de un navegador web permitiendo mejoras en la interfaz de usuario ypáginas web dinámicas.

HTML por si solo es…aburrido…muy aburrido, todo estático, nada de control, HTML es útil y necesario pero, aburrido. Y por eso se invento Javascript un lenguaje interpretado en el lado del cliente, es decir que se ejecuta en los navegadores, que ha hecho posibles todas las cosas asombrosas que estas acostumbrado a ver (Gmail, Google Docs, Youtube, Twitter, etc) así que si quieres hacer cosas igualmente asombrosas, tienes que aprender Javascript y muy bien.

CSS

CSS es un lenguaje usado para definir la presentación de un documento estructurado escrito en HTML o XML (y por extensión en XHTML). El W3C (World Wide Web Consortium) es el encargado de formular la especificación de las hojas de estilo que servirán de estándar para los agentes de usuario o navegadores.

Si HTML es el cuerpo, Javascript el cerebro, CSS es el bonito vestido. CSS es el que se encarga de toda la apariencia de los sitios y aplicaciones web. Si quieres que tus proyectos y trabajo reluzcan modernidad y conquisten por los ojos, CSS es lo que necesitas. Aprendelo muy bien o lo que hagas parecerá un horrible sitio de mediados de los noventa.

PHP

PHP es un lenguaje de programación interpretado, diseñado originalmente para la creación de páginas web dinámicas. Se usa principalmente para la interpretación del lado del servidor (server-side scripting).

WordPress usa PHP, Facebook usa PHP, infinidad de paginas, blogs, foros y comunidades corren en php (incluido este fabuloso sitio), PHP es un lenguaje que nació para la web (aunque se ha extendido a otros usos) y sigue siendo parte fundamental de la misma, aunque poco a poco otros lenguajes pretenden ocupar su lugar, no puedes dejar de saber este lenguaje.

JAVA

Java es un lenguaje de programación orientado a objetos, desarrollado por Sun Microsystems a principios de los años 90. El lenguaje en sí mismo toma mucha de su sintaxis de C y C++, pero tiene un modelo de objetos más simple y elimina herramientas de bajo nivel, que suelen inducir a muchos errores, como la manipulación directa de punteros o memoria.

Mi lenguaje de programación favorito, y no solo por el hecho de que gracias a este lenguaje tengo trabajo y pan en mi boca, sino porque esta en todos lados, desde aplicaciones de escritorio, aplicaciones web (obviamente), smarthphones, tablets (gracias a Android), en teléfonos de gama baja (J2ME) Java es una completa plataforma con muchos años en el mercado y que no puede faltar en tu repertorio.

RUBY

Ruby es un lenguaje de programación interpretado, reflexivo y orientado a objetos, creado por el programador japonés Yukihiro “Matz” Matsumoto, quien comenzó a trabajar en Ruby en 1993, y lo presentó públicamente en 1995.

El chico nuevo de la escuela (aunque ni tan nuevo que se diga) pero, no por eso menos popular. Ruby se ha ganado la simpatía y corazón de muchos desarrolladores porque hace divertido el escribir código. Se ha hecho muy popular gracias a Ruby on Rails, framework para desarrollar aplicaciones web. Ruby tiene una gran comunidad detrás de el, y día a día crecen los proyectos con este lenguaje y las ofertas de empleo también.

¿Mis razones para escoger estos lenguajes?

Estoy convencido ¿por donde empiezo?

HTML

http://www.w3schools.com/html/

Javascript

http://www.w3schools.com/js/

CSS

http://www.librosweb.es/css/

PHP

http://php.net/manual/es/index.php

Java

http://download.oracle.com/javase/tutorial/

Ruby

http://www.ruby-lang.org/es/documentation/quickstart/

http://tryruby.org/

No tardes mucho en dar el paso, si aun lo sigues pensando deja de hacerlo! Si ya estas encarrilado hacia la web felicidades!! No dejes de aprender y si recién sales de la universidad y no te enseñaron la gran cosa, sera mejor que aproveches muy bien tu conexión a Internet y tiempo y te pongas a realizar un buen tutorial, no tardes mucho, no sea que dentro de unos meses halla un nuevo lenguaje por aprender.

» Leer más, comentarios, etc...

El blog de pico.dev

Internacionalización (i18n) de campos con Hibernate

Noviembre 11th, 2011 - [Enlace local]

Java
Si estamos desarrollando un sitio web que soporta varios idiomas necesitaremos internacionalizar (i18n) los literales que aparecen en él. Esto incluye también tenerlo en cuenta y solucionarlo en los nombres, descripciones y textos que guardamos en la base de datos de las entidades de dominio y que puedan aparecer en en el html generado.



Hibernate
La primera solución que se nos ocurre para las entidades de dominio es crear un campo por cada idioma y concepto a internacionalizar. Sin embargo, esto tiene el problema de que en la base de datos el número de campos crecerá rápidamente y si tenemos muchos elementos a internacionalizar y muchos idiomas el número de campos puede ser un problema por el tamaño de fila, y aunque los limites en posgres y los límites de mysql son elevados y más que suficientes para la mayoría de los casos, con la solución anterior podemos llegar a ellos o estar peligrosamente cerca.





Diagrama entidad relación de base de datos

Primera solución (variación número columnas)


Para evitarnos problemas las buenas prácticas de diseño de las bases de datos dicen que las tablas han de estar normalizadas y siguiengo la solución anterior tendríamos variaciones en el número de columnas con lo que inclumpliríamos la primera forma normal (1FN). ¿Pero porque inclumplir esta forma normal puede ser un problema? Porque en el momento que tengamos que soportar un nuevo idioma deberemos modificar el esquema de la base de datos añadiendo un campo por cada concepto de las entidades que haya que internacionalizar. Y hacer esto en una base de datos que está en producción puede ser una fuente de problemas y un peligro. Además, en tablas con muchos registros (de unos cuantos miles o cientos de miles) añadir una columna puede ser muy lento pudiendo llegar a horas o más tiempo cosa que dependiendo del proyecto no es viable al poder tener que realizar paradas largas por mantenimiento.



La solución que voy a explicar a continuación es crear una tabla Diccionario la cual relacionaremos con las tablas de los datos de dominio (Producto) y una tabla Traduccion que relacionaremos con la tabla Diccionario y que contendrá las traducciones para cada idioma. La tabla Traduccion contendrá tres campos la clave primaria del diccionario, el idioma de la traduccion y el literal de la traducción propiamente dicho con lo que ya no tendremos variaciones en el número columnas. En la tabla Traduccion la clave primaria estará formada por la clave del diccionario y el campo locale. El esquema que tendríamos sería el siguiente:



Diagrama entidad relación de base de datos.

Producto-Diccionario 1:1

Diccionario-Traduccion 1:N
 A primera vista la tabla Diccionario no tiene mucho sentido pero nos permitirá crear en Hibernate una clase donde podremos incluir algunos métodos de utilidad de forma que podamos acceder a las traducciones más cómodamente. Para modelar este esquema con hibernate necesitaremos las siguientes entidades de dominio, la entidad Producto, Diccionario, Traduccion y TraduccionPK (necesaria en Hibernate al tener Traduccion una clave compuesta por dos campos o columnas).



// Producto.java (Código resumido)

...



@Entity

@Table(name = "Producto")

public class Producto implements Serializable {

...



@OneToOne(cascade = CascadeType.ALL)

@JoinColumn(name = "nombre_id", nullable = true)

private Diccionario nombre;



@OneToOne(cascade = CascadeType.ALL)

@JoinColumn(name = "descripcion_id", nullable = true)

private Diccionario descripcion;




...

}



// Diccionario.java

package com.blogspot.elblogdepicodev.domain;



import java.io.Serializable;

import java.util.HashMap;

import java.util.Locale;

import java.util.Map;



import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.JoinColumn;

import javax.persistence.MapKeyColumn;

import javax.persistence.OneToMany;

import javax.persistence.Table;



import org.apache.commons.lang3.StringUtils;



import com.blogspot.elblogdepicodev.misc.AppThreadLocal;



@Entity

@Table(name = "diccionario")

public class Diccionario implements Serializable {



private static final long serialVersionUID = -1210174827995726573L;



private static final int LONGITUD_TEXTO_ABREVIADO = 10;



@Id

@GeneratedValue

private Long id;



@OneToMany(cascade = CascadeType.ALL)

@JoinColumn(name = "diccionario_id")

@MapKeyColumn(name = "locale")

private Map<String, Traduccion> traducciones;




public Diccionario() {

}



public Long getId() {

return id;

}



public void setId(Long id) {

this.id = id;

}



public Map<String, Traduccion> getTraducciones() {

if (traducciones == null) {

traducciones = new HashMap<String, Traduccion>();

}

return traducciones;

}



public void setTraducciones(Map<String, Traduccion> textos) {

this.traducciones = textos;

}



//

public String getTexto() {

return getTexto(getLocale());

}



public void setTexto(String texto) {

setTexto(getLocale(), texto);

}



public String getTexto(Locale locale) {

Traduccion t = getTraducciones().get(locale.toString());

if (t == null) {

return null;

}

return t.getTexto();

}



public void setTexto(Locale locale, String texto) {

Traduccion t = getTraducciones().get(locale);

if (t == null) {

t = new Traduccion(this, getLocale().toString());

}

t.setTexto(texto);

}



//

public boolean equals(Diccionario d) {

if (d == null) {

return false;

}

return getId().equals(d.getId());

}



@Override

@SuppressWarnings({ "unchecked", "rawtypes" })

public String toString() {

Map m = new HashMap();

m.put("id", getId());

m.put("texto", StringUtils.abbreviate(getTexto(), LONGITUD_TEXTO_ABREVIADO));

return m.toString();

}



private Locale getLocale() {

return AppThreadLocal.getPreferencias().getLocale();

}

}



// Traduccion.java

package com.blogspot.elblogdepicodev.domain;



import java.io.Serializable;

import java.util.HashMap;

import java.util.Locale;

import java.util.Map;



import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.Table;



import org.apache.commons.lang3.StringUtils;



import com.blogspot.elblogdepicodev.misc.Utilidades;



@Entity

@Table(name = "traduccion")

public class Traduccion implements Serializable {



private static final long serialVersionUID = -1210174827995726573L;



private static final int LONGITUD_TEXTO_ABREVIADO = 10;



@Id

private TraduccionPK id;




@Column(length = 65536)

private String texto;



public Traduccion() {

}



public Traduccion(Diccionario diccionario, String locale) {

this.id = new TraduccionPK(diccionario, locale);

}



public TraduccionPK getId() {

return id;

}



public void setId(TraduccionPK id) {

this.id = id;

}



public String getTexto() {

return texto;

}



public void setTexto(String texto) {

this.texto = texto;

}



//

public Locale getLocale() {

return Utilidades.getLocale(id.getLocale());

}



//

public boolean equals(Traduccion t) {

if (t == null) {

return false;

}

return getId().equals(t.getId());

}



@Override

@SuppressWarnings({ "unchecked", "rawtypes" })

public String toString() {

Map m = new HashMap();

m.put("id", getId());

m.put("locale", getId().getLocale());

m.put("texto", StringUtils.abbreviate(getTexto(), LONGITUD_TEXTO_ABREVIADO));

return m.toString();

}

}



// TraduccionPK.java

package com.blogspot.elblogdepicodev.domain;



import java.io.Serializable;

import java.util.HashMap;

import java.util.Map;



import javax.persistence.Basic;

import javax.persistence.Embeddable;

import javax.persistence.ManyToOne;



@Embeddable

public class TraduccionPK implements Serializable {



private static final long serialVersionUID = 4445136951104395835L;



@ManyToOne

private Diccionario diccionario;



@Basic

private String locale;



public TraduccionPK() {

}



public TraduccionPK(Diccionario diccionario, String locale) {

this.diccionario = diccionario;

this.locale = locale;

}



public Diccionario getDiccionario() {

return diccionario;

}



public void setDiccionario(Diccionario diccionario) {

this.diccionario = diccionario;

}



public String getLocale() {

return locale;

}



public void setLocale(String locale) {

this.locale = locale;

}



//

public boolean equals(TraduccionPK t) {

if (t == null) {

return false;

}

return diccionario.equals(t.getDiccionario()) && getLocale().equals(t.getLocale());

}



@Override

@SuppressWarnings({ "unchecked", "rawtypes" })

public String toString() {

Map m = new HashMap();

m.put("dicionario", getDiccionario().toString());

m.put("locale", getLocale());

return m.toString();

}

}



// Utilidades.java

public class Utilidades {

...



public static Locale getLocale(String locale) {

String[] s = locale.split("_");

switch (s.length) {

case 1: {

return new Locale(s[0]);

}

case 2: {

return new Locale(s[0], s[1]);

}

case 3: {

return new Locale(s[0], s[1], s[2]);

}

default: {

throw new IllegalArgumentException();

}

}

}



...

}



Esta solución carga las traducciones para todos los idiomas de un diccionario cuando posiblemente solo necesitemos la traducción de un idioma en concreto, tal vez si no quisiésemos que se carguen todos los textos de las traducciones podríamos sacar el campo texto a otra tabla y relacionarla con la Traduccion con un id con lo que los campos de tablas nos quedarían: Traduccion (diccionario_id, locale, texto_id), Texto (id, texto). Aunque con esta última solución necesitamos lanzar una sql más por cada texto que queramos acceder.



Referencia:

http://www.hibernate.org/

http://www.postgresql.org/about/

http://dev.mysql.com/doc/refman/5.0/en/column-count-limit.html

http://es.wikipedia.org/wiki/Normalizaci%C3%B3n_de_bases_de_datos

http://support.microsoft.com/kb/283878/es

» Leer más, comentarios, etc...

Viricmind Labs

Añadir filtro de búsqueda en una tabla con jQuery

Noviembre 11th, 2011 - [Enlace local]

Gnome System Search IconPara completar el anterior artículo que escribí sobre ordenación de tablas con jQuery [1] hoy os hablaré sobre la creación de un filtro de búsqueda para nuestras tablas, algo prácticamente imprescindible hoy en día en multitud de aplicaciones de gestión que presentan parte de sus datos de forma tabular.

El código que veréis a continuación es bastante sencillo, no permite búsquedas con operadores lógicos (AND, OR, NOT), ni que se restrinjan a columnas concretas, sin embargo sí que aprovecha toda la potencia de las expresiones regulares para realizar búsquedas relativamente complejas. Para mi gusto es más importante la característica de los operadores lógicos y las restricciones a columnas concretas que la posibilidad de usar expresiones regulares, pero creo que no vale la pena complicar el artículo por algo que no tiene demasiada miga a nivel técnico.

El código es tal que así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function setup_searchable (selector) {
	var search_input = $("#"+selector+"-searcher");
 
	search_input.keyup ((function () {
		var tbody = $("#"+selector+"-table").find('tbody');
		var hidden_rows = tbody.find('tr');
 
		var searcher = function () {
			var search_text = search_input.val().toUpperCase();
 
			tbody.html('');
 
			var shown_rows = hidden_rows.filter (function () {
				var re = new RegExp (search_text),
					 matched = false;
 
				$(this).find('td').each(function (i2) {
					matched = matched || ($(this).text().toUpperCase().match(re) != null);
				});
 
				return matched;
			});
 
			tbody.append (shown_rows);
		};
 
		return searcher;
	})());
}

En este ejemplo trabajamos con dos elementos básicos, un elemento input de tipo texto y una tabla. El código asume que el selector se referirá a su identificador único id, y que los respectivos ids tendrán una estructura del tipo selector-searcher para el elemento input, y selector-table para la tabla.

Sobre el código, puede ser interesante notar que uso el evento keyup en vez del evento change, esto permite que la tabla se actualice en tiempo real, en contraposición a lo que sucedería con change, que necesita que apretemos la tecla Enter y cambiemos o cambiemos el foco de nuestro cursor. Otro detalle importante es que guardamos en memoria la totalidad de las filas antes de efectuar el filtrado, de modo que evitamos perderlas, y cuando cambiamos los criterios de búsqueda no tenemos que recargar ningún dato desde el servidor. Este último hecho implica que conviene llamar a la función setup_searchable cada vez que recarguemos la tabla con nuevos datos desde el servidor, pues de lo contrario nuestro buscador trabajará con datos "antiguos".

Algunas mejoras obvias para este código aparte de las mencionadas anteriormente serían las siguientes:

Espero que esto le resulte útil a alguien, agradeceré cualquier comentario y propuesta de mejora, saludos! :)

  1. Ordenación de elementos del DOM con Javascript y jQuery

» Leer más, comentarios, etc...

Picando Código

¡Mañana RubyConf Uruguay!

Noviembre 10th, 2011 - [Enlace local]

RubyConf Uruguay 2011

RubyConf Uruguay 2011

Mañana comienza la segunda edición de RubyConf Uruguay. Personalmente estoy muy entusiasmado y ansioso con el evento. La primera edición estuvo increíble y superó mis expectativas, así que este año espero lo mismo y más.

A las 9 estaremos por ahí para acreditarnos y seguramente compartir un café con el resto de la comunidad. En el trabajo estuvimos haciendo campaña para llevar gente y logramos triplicar los asistentes (el año pasado fuimos 2 de la empresa :| ). Supongo que dado el éxito de la primer instancia, y la difusión boca en boca, la asistencia de este año supere la del anterior, todo basado en especulaciones…

Recuerden, mañana a las 9 en el auditorio de la Torre de las Telecomunicaciones (también conocida como “la torre de Antel”) en Guatemala 1075. Por si no han leído la agenda todavía, les comento que el nivel de las charlas es excelente, con temas excesivamente magníficos.

Al igual que el año pasado, voy a abusar del WiFi proporcionado en la conferencia para inundar mis perfiles en Twitter e Identi.ca con información y comentarios en vivo del evento.

Les dejo los enlaces de los posts de la primer RubyConf Uruguay realizada el año pasado:

Y si quieren un poco de inspiración, no se pierdan la keynote:

¡Nos vemos mañana en RubyConf!

» Leer más, comentarios, etc...

Picando Código

Jornada de conferencias sobre Datos Abiertos en Montevideo

Noviembre 10th, 2011 - [Enlace local]

Difundo información de una jornada de especial interés para lectores del blog. Primer instancia en que se dará a conocer información sobre el concurso Desarrollando América Latina del que iré publicando más información próximamente. No se lo pierdan:

Desarrollando América Latina

Desarrollando América Latina

La Diaria y el concurso Desarrollando América Latina los invitan a participar este lunes 14 de noviembre de una jornada de conferencias sobre Datos Abiertos. Expondrán miembros del equipo de desarrollo de datos abiertos de Intendencia de Montevideo, quienes contarán sus experiencias en el camino recorrido en la materia, y los retos para el futuro.

Cerrará el evento Evan Henshaw presentando el concurso Desarrollando América Latina, que promueve el desarrollo simultaneo en 6 países de la región de aplicaciones informáticas novedosas que ayuden a resolver los problemas de la sociedad. Durante la presentación se despejarán dudas sobre el concurso que tendrá lugar el próximo 3 y 4 de diciembre durante 30 horas consecutivas.

Las conferencias tendrán lugar este lunes 14 de noviembre, en el Museo Nacional de Artes Visuales, Tomás Giribaldi 2283 esq. Julio Herrera y Reissig – Parque Rodó, a partir de las 18hs. Por más información contactarse con la organización de Desarrollando América Latina al correo dal.uruguay@gmail.com

Invitan: Desarrollando América Latina, La Diaria, Cubox SA, Intendencia de Montevideo, AGESIC, Museo Nacional de Artes Visuales.

Cómo llegar: http://www.mnav.gub.uy/cms.php?id=informacion

Acerca de Datos Abiertos:

Datos abiertos es una tendencia incipiente con gran potencial de desarrollo. Individuos y organizaciones recaban una amplia gama de datos para realizar sus tareas. El Gobierno es particularmente importante en este contexto, por la cantidad de datos que recoge de empresas, de ciudadanos, de gestión, de salud, geográficos y financieros entre otros. En este documento se describen conceptos e ideas base de Datos Abiertos de Gobierno.

http://www.agesic.gub.uy/innovaportal/v/1544/1/agesic/conceptos_basicos_de_datos_abiertos.html?menuderecho=2

Acerca de Desarrollando América Latina

Desarrollando América Latina es la Copa América del desarrollo digital. El 03 y 04 de Diciembre, por 30 horas consecutivas, los mejores desarrolladores web de 6 países latinoamericanos se reunirán en sus respectivos países a trabajar para encontrar soluciones digitales a problemas sociales.

http://desarrollandoamerica.org/%C2%BFque

¡Nos vemos ahí!

» Leer más, comentarios, etc...

Información legal y técnica