Picando Código
Libro: xkcd – volume 0
Febrero 15th, 2011 - [Enlace local]
Hace poco compré un par de libros en Amazon. Todo empezó leyendo el sitio web del webcómic The Oatmeal, donde anunciaba la reedición de su libro: 5 Very Good Reasons to Punch a Dolphin in the Mouth (And Other Useful Guides)
. El libro contiene 160 páginas de los cómics de The Oatmeal que son mega hiper increíbles, además de 25 cómics inéditos y un póster con “Why I believe printers were sent from hell“.
Si bien el libro no estará disponible hasta el primero de marzo, decidí pre ordenarlo. Ni lento ni perezoso, Amazon me recomendó xkcd: volume 0. Se trata del libro del famoso webcómic xkcd, decidí comprar ambos libros ya que iba a realizar la compra.
¿Qué puedo decir de xkcd? Es un webcómic creado por Randall Munroe sobre romance, sarcasmo, matemáticas y lenguaje. Su obra es una genialidad que combina todos estos elementos, y por esto se ha convertido en un clásico de culto. Randall Munroe es un científico con un título en física que abandonó su trabajo en la NASA para ponerse a dibujar figuras de palitos teniendo sexo. Si todavía no lo conocen, dejen de leer este post, y vayan a leerlo.
Con unos compañeros de trabajo comentábamos hace un tiempo: en las entrevistas de trabajo a los programadores, habría que hacerles pregunas de xkcd. Por ejemplo: ¿quién era Bobby Tables y porqué hizo enojar a su escuela? ¿alguna vez probaron alcanzar el Ballmer Peak? etc.
El libro es el primero en compilar algunos de los cientos de cómics del sitio. Éstos se pueden leer gratis en internet, pero no hay como el papel para leerlo. No todos están incluidos, ya que algunos originales de alta resolución se perdieron en la historia de xkcd (aunque los originales en papel siguen vivos). Munroe decidió hacer un compilado con sus cómics preferidos y agregó algunas notas, puzzles, acertijos, dibujos y demás en los márgenes de las páginas.
Cuenta con 120 páginas, marcadas con el sistema trinario. Es similar al sistema binario, pero con 0,1 y 2. Cada página incluye uno o varios cómics, por lo que algunos están bastante ampliados, mientras que otros se reducen un poco para dar espacio a más de uno en la misma página. A lo largo del libro encontramos códigos QR, y varios códigos cifrados, que extienden la experiencia de lectura a la diversión de descifrar estos códigos y mensajes ocultos…
Si son lectores asiduos de xkcd, es un artículo de colección muy interesante. No solo podemos tener en nuestra biblioteca un clásico de la historieta moderna (manifestado a través de internet), sino que tiene el agregado de incluir contenido exclusivo del libro. Soy partidario de libros que provean más que una simple experiencia de lectura. Y este libro lo hace, extendiendo el concepto que hace grande a xkcd al papel.
Un libro más que agrego a mi colección de colecciones de (web)cómics, y que recomiendo a todos los lectores de xkcd.
Otra experiencia satisfactoria comprando en Amazon. He comprado varios libros ahí con una experiencia excelente. Hace poco ordené un libro que todavía no había salido y, por un supuesto error de ellos, llegaría tres meses después de la fecha estimada. Hablé con atención al cliente para cancelar la orden, ya que podía conseguirlo antes por otros medios. Pero me comentaron que ya había sido embarcado (algo que no entendía si el libro no estaba disponible aún), y no podían cancelar la orden. Tras varios correos de ida y vuelta, y resignado a esperar los 3 meses, el libro llegó a mi puerta al día siguiente de su fecha de lanzamiento.
Esta vez pedí que me enviaran todo junto, para pagar menos envío (por más que el libro de Oatmeal estaría disponible recién a partir de marzo). Pero recibí un correo de Amazon donde me informaban que una porción de la orden había sido enviada para darme un servicio mas rápido. Aclaraban en el correo, que no me cobrarían gastos extra de envío, y el resto de mi orden sería enviada ni bien estuviera disponible.
Para mi sorpresa, unos días después tenía en mis manos el libro xkcd: volume 0
» Leer más, comentarios, etc...
Variable not found
WebGrid en modo Ajax con MVC 3
Febrero 15th, 2011 - [Enlace local]
En posts anteriores hemos hablado sobre el helper WebGrid (aquí y aquí), y las facilidades que nos ofrece a la hora de crear rejillas de datos con paginación y ordenación. En todos los ejemplos que vimos, cada cambio de página o de criterio de ordenación forzaba una recarga completa de la vista, lo cual es bastante correcto y válido en la mayoría de escenarios.
Sin embargo, WebGrid también ofrece la posibilidad de recargar (al menos visualmente, como veremos después) únicamente la rejilla de datos, por lo que se consigue un comportamiento muy al estilo Ajax, como el que podemos conseguir con otras soluciones. Y de nuevo de forma realmente sencilla, en dos simples pasos.
En primer lugar, en la instanciación del objeto WebGrid, debemos suministrar un valor al parámetro ajaxUpdateContainerId, indicando el identificador del elemento en cuyo interior generaremos la rejilla de datos, por ejemplo así:
WebGrid grid = new WebGrid(
..., // Otros parámetros del constructor
ajaxUpdateContainerId: "contenedor-grid"
Y finalmente, ya dentro del marcado de la vista, debemos asegurar que la llamada a
GetHtml() del helper se realice dentro de un contenedor con el identificador especificado anteriormente:fillEmptyRows: true,
alternatingRowStyle: "fila-alternativa",
headerStyle: "encabezado-grid",
footerStyle: "pie-grid",
mode: WebGridPagerModes.All,
...
})
</div>
Y eso es todo. Sin necesidad de modificar el Controlador, ni por supuesto el Modelo, las operaciones de desplazamiento entre páginas, cambio de columna o sentido de ordenación, no recargarán la página completa, sino únicamente el contenedor indicado.
Parece magia, eh? ;-)
Tras bambalinas
Pues no, no hay nada mágico, lo que está ocurriendo por detrás es bastante simple: al activarse el modo Ajax, simplemente por el hecho de asignar un valor aajaxUpdateContainerId, WebGrid modificará la forma de generar los enlaces del paginador y las columnas ordenables, de forma que no guiarán al navegador hacia la acción de refresco, sino ejecutarán un script.En este script se utiliza el método load() de jQuery para solicitar de forma asíncrona la página completa, invocando la misma acción actual, y suministrándole los parámetros que necesita, o sea, la página actual, orden o sentido de ordenación, dependiendo de la operación realizada.
Del resultado de esta petición Ajax (la página completa de nuevo), jQuery seleccionará sólo el fragmento cuyo identificador coincida con el indicado por
ajaxUpdateContainerId, y sustituirá el contenido del elemento con ese mismo identificador en la vista actual. De esa forma, se habrá actualizado el grid sin necesidad de recargar visualmente la página completa, aunque internamente sí se habrá generado y enviado al cliente completa. La verdad, esta forma de conseguir el efecto Ajax, un poco a lo bestia, recuerda un poco al celebérrimo UpdatePanel :-O.
Y ya puestos a criticar (constructivamente siempre, claro ;-)), seguro que podría haberse conseguido una implementación no intrusiva, de forma que un usuario con los scripts desactivados obtuviese el funcionamiento “por defecto” del Grid, con recarga total de la página.
Pero bueno, al menos es interesante saber que WebGrid cuenta con la posibilidad de ajaxificarse, y conocer el funcionamiento de esta característica, por si en alguna ocasión nos encontramos con ella.
Dejo en SkyDrive un proyecto de demostración de WebGrid en modo Ajax (VS2010+MVC3+SQLExpress), así como los ejemplos de los post anteriores sobre el mismo tema, por si os interesa verlo en funcionamiento.Publicado en: Variable not found.
» Leer más, comentarios, etc...
MadeInFlex
Clear Toolkit para el desarrollo de aplicaciones Flex
Febrero 15th, 2011 - [Enlace local]
En Febrero del 2009 Farata Systems anunció en su blog que comenzaba el proceso de liberación bajo licencia de código abierto su producto Clear Toolkit.
En aquel momento estaba en la versión 3.1 y estaba compuesto por:
- Clear Data Builder 3.1: Un plugin de eclipse que permitía la generación de código para hacer operaciones CRUD, tomando como base una sentencia SQL o una clase Java (DTO).
- DTO2Fx: una utilidad que permite la generación de las clases en ActionScript partiendo de una clase correspondiente en Java.
- Log4Fx: Un plugin para Eclipse que automatiza y hace más amigable la generación de trazas en la aplicación.
- Fx2Ant: Una utilidad que genera scripts ant basado en el proyecto Flex
- clear.swc: Una biblioteca de componentes Flex que incluye componentes que hacen facilitan la implementación de las funcionalidades CRUD en los proyectos.
Específicamente sobre la biblioteca clear.swc se han escrito varios artículos explicando su funcionamiento y cómo se usa en los proyectos:
- Introducing Enhanced Flex Components from Clear Toolkit Framework
- Building an Enterprise Framework – Enterprise Development with Flex, Part 1
- Building an Enterprise Framework – Enterprise Development with Flex, Part 2
- Building an Enterprise Framework – Enterprise Development with Flex, Part 3
El producto ha evolucionado, en la actualidad se encuentra en la versión 4.1 y se continúa desarrollando. Esta versión permite la generación del código necesario para realizar las operaciones CRUD, utilizando Hibernate, partiendo de clases Java (DTO) y de interfaces en las cuales se incluyen anotaciones propias del framework, y que al ser compiladas provocan la generación del código. Ofrece también una solución a la sincronización de datos, funcionalidad que no está presente en BlazeDS y sí en LiveCycle Data Services.
Las diferencias entre BlazeDS+Clear Toolkit y LiveCycle Data Services se abordan en el artículo Open source alternatives to LiveCycle Data Servcies.
Otra de las funcionalidades presentes en esta última versión es la posibilidad de hacer “lazy loading” desde flex. Para esto se incluye en la clase Java una anotación que indica la relación (One-to-Many o Many-to-One) y el framework genera todo el código necesario tanto en Java como en ActionScript para esta funcionalidad.
Existen dos screencast que muestran muy claramente cómo se utiliza esta funcionalidad, estos videos se pueden encontrar en:
- http://www.cleartoolkit.com/videos/cdb4.1/Episode1UsingEntities/
- http://www.cleartoolkit.com/videos/cdb4.1/Episode2HierarchicalCollectionsWithEntities/
Los desarrolladores trabajan en la integración con Spring, lo que seguramente estará disponible en versiones futuras.
La documentación de las clases tanto de la biblioteca clear.swc como de java se puede leer en:
- http://help.faratasystems.com/en_US/cleartoolkit/reference/flex/4/
- http://help.faratasystems.com/en_US/cleartoolkit/reference/BlazeDS/4/
El proyecto continúa hospedado en Sourceforge desde donde se puede descargar la última versión del producto así como acceder a la documentación, a los fórums y al código fuente.
Les recomiendo que lo prueben, una vez que se conoce como funciona se ahorra mucho tiempo en la implementación de la funcionalidad CRUD en los proyectos.
» Leer más, comentarios, etc...
MadeInFlex
Grandes expectativas para Flash Player y AIR en el 2011
Febrero 15th, 2011 - [Enlace local]
En estos días se está celebrando el Mobile World Congress en Barcelona. Como es habitual, Adobe Systems Incorporated tiene presencia en este congreso y ha dado unas noticias realmente asombrosas: actualmente se puede desarrollar aplicaciones con Adobe AIR para más de 84 millones de smartphones y tablets con Android y iOS. Hay disponibles miles de aplicaciones en el Android Market y en Apple App Store. Para finales del 2011, Adobe espera que más de 200 millones de smartphones y tablets soporten AIR.
os dejo unos links para que podais ampliar esta información:
link 1
link 2
» Leer más, comentarios, etc...
Ingenieria de Software / Software Engineering / Project Management / Business Process Management
Predicciones de TI segun IDC
Febrero 15th, 2011 - [Enlace local]
Mobile, Gobierno, Cloud, Redes Sociales, Las predicciones de IDC para 2011
http://cioperu.pe/articulo/6236/las-predicciones-de-idc-para-el-2011.aspx
» Leer más, comentarios, etc...
DGG
Instalación y configuración DNS en Ubuntu
Febrero 14th, 2011 - [Enlace local]
El DNS es una base de datos distribuida y jerárquica que almacena información asociada a nombres de dominio en redes como Internet. Aunque como base de datos el DNS es capaz de asociar diferentes tipos de información a cada nombre, los usos más comunes son la asignación de nombres de dominio a direcciones IP y la localización de los servidores de correo electrónico de cada dominio.
Estos son un resumen de los pasos para instalar un servidor DNS en un servidor Ubuntu:
1.-Instalar software
Tenemos que instalar el paquete bind9. Si utilizamos apt-get ejecutamos la siguiente instrucción:
sudo apt-get install bind9
En el caso de que no tengamos disponible la utilidad apt-get tendremos que instalar el paquete y TODAS sus dependencias por el método tradicional:
sudo dpkg -i bind9_9.3.2-2ubuntu1.12_i386.deb
2.- Creación del fichero named.conf.local
Tenemos que editar el siguiente fichero para definir las zonas (nombres de dominio) que queramos configurar:
sudo vi /etc/bind/named.conf.local
E introducimos lo siguiente, reemplazando 2 variables:
- Reemplazamos server.com por el dominio que nosotros deseemos:
- Reemplazamos 0.168.192 por la dirección de la red al revés, por ejemplo, si estuvieramos en una red 10.228.20.x, introduciríamos 0.20.228.10
# This is the zone definition. replace example.com with your domain name
zone "server.com" {
type master;
file "/etc/bind/zones/server.com.db";
};
# This is the zone definition for reverse DNS. replace 0.168.192 with your network address in reverse notation - e.g my network address is 192.168.0
zone "0.168.192.in-addr.arpa" {
type master;
file "/etc/bind/zones/rev.0.168.192.in-addr.arpa";
};
3.- Editar el fichero de opciones named.conf.options
sudo vi /etc/bind/named.conf.options
En este fichero sólo tenemos que establecer la dirección IP de nuestros DNS de la red. En el caso de que el servidor DNS que estamos montando no sepa resolver el dominio, reenviará la petición a estos DNS
forwarders {
# Replace the address below with the address of your provider's DNS server
123.123.123.123;
123.123.123.124;
};
4.- Crear los ficheros de configuración de nuestra zona:
sudo mkdir /etc/bind/zones
Miramos el nombre del fichero que habíamos definido en el fichero /etc/bind/named.conf.local, en nuestro caso es /etc/bind/zones/server.com.db
y cremos el fichero:
sudo vi /etc/bind/zones/server.com.db
En este fichero ya es donde tenemos que definir la equivalencia entre ips y dominios:
;
; BIND data file for local loopback interface
;
$TTL 604800
@ IN SOA server.com. root.server. (
1 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS server.com.
server.com IN A 1.1.1.1
server1 IN A 1.1.1.2
IMPORTANTE: Eliminar todos los comentarios de la forma //, A mí me dio problemas. Y ojo también con los “.” después del nombre del dominio, no se pueden eliminar.
El siguiente punto de configuración es crear el fichero de reverse DNS zone, que a partir de una ip nos dirá el dominio.
Nos fijamos en el fichero que habíamos definido en el fichero /etc/bind/named.conf.local, en nuestro caso teníamos: file “/etc/bind/zones/rev.0.168.192.in-addr.arpa”;
Por lo que el fichero sería:
sudo vi /etc/bind/zones/rev.0.168.192.in-addr.arpa
//replace server.com with yoour domain name, ns1 with your DNS server name.
// The number before IN PTR server.com is the machine address of the DNS server. in my case, it's 1, as my IP address is 192.168.0.1.
@ IN SOA ns1.example.com. admin.example.com. (
2006081401;
28800;
604800;
604800;
86400
)
IN NS ns1.server.com.
1 IN PTR server.com
120 IN PTR server2
IMPORTANTE: El número “1″ que tenemos en la última fila es la dirección de la máquina de la red, por ejemplo, si tenemos un servidor con ip 192.168.0.120, el número que tenemos que poner es 120.
5.- Configurar este DNS en nuestra máquina (/etc/resolv.conf)
Introducimos el nuevo servidor DNS y dejamos también por si acaso el servidor DNS original de nuestra red.
search server.com nameserver 192.168.0.1 nameserver 1.1.1.1
6.- Reiniciar el servicio bind y probar el servidor DNS
Por último reiniciamos el servicio bind y probamos que funciona.
sudo /etc/init.d/bind9 restart
Hay varias utilizades para saber si funciona: dig, nslookup y ping:
dig server.com dig server1.server.com nslookup 192.168.0.1 ping server1.server.com
Referencia:
https://help.ubuntu.com/6.06/ubuntu/serverguide/C/dns.html
https://help.ubuntu.com/community/BIND9ServerHowto
http://es.wikipedia.org/wiki/Domain_Name_System
Filed under: mini-tutorial Tagged: dns
» Leer más, comentarios, etc...
Picando Código
Aprendiendo Ruby parte 3 – Clases, objetos y demás
Febrero 14th, 2011 - [Enlace local]
Siguiendo con la serie sobre Ruby, con este post cubro parte del capítulo 3 del libro Pickaxe. Respecto a la orientación a objetos del lenguaje, todo lo que manipulamos en Ruby es un objeto. Voy a copiar y pegar el código que hice siguiendo el ejemplo del libro. Creo que está bastante simple, y se puede ir entendiendo y viendo cómo maneja las cosas Ruby con solo mirar el código.
El libro explica muchos conceptos básicos de orientación a objetos que voy a omitir, suponiendo que los lectores ya tienen conocimiento del tema. Voy a hacer un resumen de referencia, con algunos detalles, que muestre lo específico del lenguaje. Así que este post es algo así como algo para tener de referencia, pero no voy a detallar demasiado los conceptos.
Veamos la estructura de un objeto básico, con algunas de sus características:
# -*- coding: utf-8 -*- class Libro attr_accessor :isbn, :price #Crea ambos (getter y setter) #Constructor - llamado con Libro.new def initialize(isbn, precio) #Variables de instancia: @variable @isbn = isbn @precio = precio end #Método que envía a un objeto cuando quiere mostrarse como String #Similar a toString() de Java def to_s "Libro - ISBN: #{@isbn} - Precio: #{@precio}" end end
Acá tenemos una clase “Libro”, con un constructor que recibe dos parámetros y establece esos valores en las variables de instancia, y un método to_s para mostrar el objeto. Por ahora las variables de instancia son privadas y no tienen forma de accederse desde afuera, o cambiar su valor. Para esto Ruby podemos hacer lo siguiente:
def isbn @isbn end def isbn=(new_isbn) @isbn = new_isbn end
De esta manera creamos métodos para acceder a las variables, al estilo “getter y setter” de Java:
Como los getter y setter son tan comunes, Ruby provee las siguientes atajos:
attr_reader :isbn, :price #Crea el "get" del atributo attr_writer :isbn, :price #Crea el "set" del atributo attr_accessor :isbn, :price #Crea ambos (getter y setter)
Bien, a continuación pego el código que sigue el ejemplo del libro. Tenemos tres archivos:
libro.rb – la clase “libro”
# -*- coding: utf-8 -*- class Libro attr_accessor :isbn, :price #Crea ambos (getter y setter) #Constructor - llamado con Libro.new def initialize(isbn, precio) #Variables de instancia: @variable @isbn = isbn @precio = precio end #Método que envía a un objeto cuando quiere mostrarse como String #Similar a toString() de Java def to_s "Libro - ISBN: #{@isbn} - Precio: #{@precio}" end end
csv_reader.rb – El lector de CSV:
require 'csv' #Dependencia externa require_relative 'videogame' #Dependencia relativa a este archivo class CsvReader def initialize @libros = [] end def leer_datos_csv(nombre_archivo_csv) CSV.foreach(nombre_archivo_csv, headers: true) do |row| @libros << Libro.new(row['isbn'], row['precio']) end end def mostrar_todos @libros.each do |libro| puts libro end end end
Y por último el app.rb con el código que usa todo esto:
#!/usr/bin/ruby require_relative 'csv_reader' reader = CsvReader.new ARGV.each do |nombre_archivo| STDERR.puts "Procesando #{nombre_archivo}" reader.leer_datos_csv(nombre_archivo) end reader.mostrar_todos
Como ven, se usa ARGV, el array de parámetros recibidos por el script. En mi caso creé un archivo datos.csv con esta info:
“978-1-93435-608-1″,”49.95″
“978-0136006633″,”120.74″
Y lo pasé como parámetro al script de arriba:
[fernando@hoth app]$ ./app.rb datos.csv Procesando datos.csv Libro - ISBN: 978-1-93435-608-1 - Precio: 49.95 Libro - ISBN: 978-0136006633 - Precio: 120.74
Bien, visto esto, pasamos a control de acceso a una clase. En Ruby hay tres niveles de protección: public, protected y private. La diferencia de Ruby con otros lenguajes es que los métodos protected pueden ser llamados de cualquier instancia de las clases que lo definen y sus subclases. Y el acceso de control es determinado dinámicamente, por lo que los errores saltan cuando se ejecuta el código.
Cuando definimos un método sin especificar el acceso, el valor por defecto es public. Y tenemos dos formas de especificar el acceso de los métodos:
class Clase def metodo #por defecto es public end protected #A partir de aca, los métodos son protected def metodo0 #protected end def metodo1 #protected end private #A partir de este punto, los métodos son privados def metodo2 #privado end #otra forma de definir el acceso: public :metodo0 #protected :metodo #private :metodo end
Bien, la última parte del capítulo 3 del libro habla sobre variables. En Ruby las variables son referenicas a objetos. Por lo tanto sucede lo siguiente:
[fernando@hoth app]$ irb irb(main):001:0> persona = "Fernando" => "Fernando" irb(main):002:0> persona2 = persona => "Fernando" irb(main):003:0> puts persona.object_id 18425820 => nil irb(main):004:0>puts persona2.object_id 18425820 => nil irb(main):005:0> persona2[8] = "s" => "s" irb(main):006:0> puts persona Fernandos => nil
Esto pasa también en Java, y en Ruby lo que podemos hacer para almacenar una copia del primer objeto en la segunda variable (para crear un objeto nuevo, y por ende referenicar a un objeto distinto) es usar dup. Otro método interesante que podemos usar en Ruby es freeze. Al hacer objeto.freeze, Ruby lanzará un RuntimeError si otra parte de nuestro código intenta modificar objeto.
Para este capítulo, como dije en los posts anteriores, no entré mucho en detalle. Fue todo más que nada una pasada de cosas que tiene Ruby. Es que a esta altura, ya empecé a hacer pruebas, y tengo ganas de programar.Ya estuve mirando algo más de Ruby On Rails, y leí un poco de Sinatra.
En principio ya estuve haciendo una prueba básica que subí en GitHub: RSS Script. Entre otras tantas ideas, tenía una idea para una aplicación en Ruby que necesitaba leer RSS, así que ahí está el resultado. Fue bastante rápido y simple, no es nada del otro mundo el código, pero a lo mejor queda como algo terminado algun día.
También estoy por juntarme con más gente para desarrollar una aplicación simple, pero más completa. Vamos a ver qué sale, ya estaré contando por acá.
Comparte:
» Leer más, comentarios, etc...
Variable not found
Enlaces interesantes 30
Febrero 13th, 2011 - [Enlace local]
Estos son los enlaces publicados en Variable not found en Facebook y Twitter desde el domingo, 06 de febrero de 2011 hasta el domingo, 13 de febrero de 2011.
Espero que te resulten interesantes. :-)
- Conditional Validation in ASP.NET MVC 3 - UK Premier Support for Developers - Site Home - MSDN Blogs (vía Javier Torrecilla)
Fecha: 10/02/2011 - David Noël_hayden: SessionState Attribute in ASP.NET MVC 3
Fecha: 10/02/2011 - WCF Data Services Team Blog: New JavaScript library for OData and beyond.
Fecha: 10/02/2011 - "Stackoverflow Exceptions with Html.Action" by K. Scott Allen
Fecha: 09/02/2011 - Gisela Torres: Google Maps API v.3.0 y ASP.NET MVC 3 con Razor
Fecha: 09/02/2011 - ASP.NET MVC 3 video training de pluralsight, gratis durante 48 horas.
Fecha: 09/02/2011 - Herramientas de línea de comando importantes de .NET 4.0.
Fecha: 09/02/2011 - ASP.NET MVC performance tips, by Marcin Doboz.
Fecha: 09/02/2011 - Gisela Torres: Razor View Engine para ASP.NET MVC 3.
Fecha: 07/02/2011 - Antonio Ortiz: Larga vida a Sir clive Sinclair: 'El Spectrum volverá a la vida 30 años después'
Fecha: 07/02/2011 - Habrá que echarle un vistazo: jQuery file upload.
Fecha: 07/02/2011 - Nuevos atributos de validación en ASP.NET MVC 3 futures.
Fecha: 07/02/2011 - ¿Qué ocurre si falla el constructor de un IDisposable?
Fecha: 07/02/2011
Publicado en: Variable not found
» Leer más, comentarios, etc...
Bitácora de Javier Gutiérrez Chamorro (Guti)
Comentarios de cine (XVIII)
Febrero 13th, 2011 - [Enlace local]
Os presento la décimo octava entrega de los comentarios de cine: - 12 trampas: 5/10. La acción de las 12 pruebas, no es muy original, pero tampoco aburre en ningún momento. - Capitalismo una historia de amor: 6/10. Criticando esta vez la desvirtuación del capitalismo, es como de costumbre incisivo, y aunque no está exento [...]Artículos relacionados:
» Leer más, comentarios, etc...
programania
Cuadernos del software
Febrero 12th, 2011 - [Enlace local]
En programania escribimos sobre todo aquello relacionado con el desarrollo de software. Nos interesa: metodologías, lenguajes, herramientas, etc.
» Leer más, comentarios, etc...
Arragonán
Autentificación HTTP con Grails
Febrero 11th, 2011 - [Enlace local]
Todo el mundo en algún momento ha necesitado implementar autentificación HTTP en una aplicación o página web(o no
).
Con grails me ha vuelto a tocar hacerlo, por medio de un filtro para que fuera muy fácil de poner o quitar. El código queda como algo así:
class AuthFilters {
def USERNAME = "user"
def PASSWORD = "pass"
static filters = {
httpAuth(uri:"/**") {
before = {
def authHeader = request.getHeader('Authorization')
if (authHeader) {
def usernamePassword = new String(authHeader.split(' ')[1].decodeBase64())
if (usernamePassword == "$USERNAME:$PASSWORD") {
return true
}
}
response.setHeader('WWW-Authenticate', 'basic realm="myRealm"')
response.sendError(response.SC_UNAUTHORIZED)
return false
}
}
}
}
¿Hace falta explicar algo?
» Leer más, comentarios, etc...
Monocaffe
CoffeScript and Canvas
Febrero 10th, 2011 - [Enlace local]
I keep playing with CoffeeScript, and what better way than using canvas!
<html>
<head>
<title>CoffeScript Canvas</title>
<script src="coffee-script.js"></script>
<script type="text/coffeescript">
draw = () ->
canvas = document.getElementById('coffee')
if canvas.getContext
ctx = canvas.getContext('2d')
ctx.fillStyle = "rgb(200,0,0)"
ctx.fillRect(10, 10, 55, 50)
ctx.fillStyle = "rgba(0, 0, 200, 0.5)"
ctx.fillRect(30, 30, 55, 50)
draw()
</script>
<style type="text/css">
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="coffee" width="150" height="150"></canvas>
</body>
</html>
Well, it's basically the same as with JavaScript.
» Leer más, comentarios, etc...
Bitácora de Javier Gutiérrez Chamorro (Guti)
VIM
Febrero 9th, 2011 - [Enlace local]
Los editores de texto, son un tipo de aplicación que en general fascina a los programadores, en mayor medida, cuanto más tiempo llevan en el gremio.
Vim (Vi Improved) es una evolución del tradicional vi, iniciada en 1991 por Bram Moolenaar, con la misma esencia de vi, a la que se añaden características más avanzadas en cuanto a facilidad de uso. Sin embargo, no nos engañemos, pues Vim va a tener las mismas críticas y alabanzas de vi.
En su última versión 7.3, Vim se ofrece para multitud de plataformas que oficialmente van desde Win32 y Win64, o UNIX, hasta Mac, DOS, OS/2, Amiga. Extra oficialmente hay compilaciones para Android, QNX, VMS, Windows CE, etc.
He tenido necesidad de utilizar editores de la vieja escuela como el caso de vi, edlin o emacs, aunque no soy un amante de ellos. Encuentro mucho más productivos los desarrollos más modernos y complejos como EmEditor, AkelPad, Kate o simplemente Joe.
Donde si le encuentro una gran utilidad a Vim, es como herramienta de aprendizaje de vi. Su GUI, los menús, y la documentación incluída, son la ayuda perfecta en las prácticas con Vim, y por ende, con vi.
Huelga decir que al igual que vi, es gratuito y de código abierto, pero además, se ofrece traducido al castellano. Es veloz en la mayoría de operaciones, pero su código multiplataforma le pasa factura, y no es tan compacto como podríamos esperar. Eso si, trabaja de manera portable por defecto.
» Leer más, comentarios, etc...
Bitácora de Javier Gutiérrez Chamorro (Guti) » Programación
VIM
Febrero 9th, 2011 - [Enlace local]
Los editores de texto, son un tipo de aplicación que en general fascina a los programadores, en mayor medida, cuanto más tiempo llevan en el gremio.
Vim (Vi Improved) es una evolución del tradicional vi, iniciada en 1991 por Bram Moolenaar, con la misma esencia de vi, a la que se añaden características más avanzadas en cuanto a facilidad de uso. Sin embargo, no nos engañemos, pues Vim va a tener las mismas críticas y alabanzas de vi.
En su última versión 7.3, Vim se ofrece para multitud de plataformas que oficialmente van desde Win32 y Win64, o UNIX, hasta Mac, DOS, OS/2, Amiga. Extra oficialmente hay compilaciones para Android, QNX, VMS, Windows CE, etc.
He tenido necesidad de utilizar editores de la vieja escuela como el caso de vi, edlin o emacs, aunque no soy un amante de ellos. Encuentro mucho más productivos los desarrollos más modernos y complejos como EmEditor, AkelPad, Kate o simplemente Joe.
Donde si le encuentro una gran utilidad a Vim, es como herramienta de aprendizaje de vi. Su GUI, los menús, y la documentación incluída, son la ayuda perfecta en las prácticas con Vim, y por ende, con vi.
Huelga decir que al igual que vi, es gratuito y de código abierto, pero además, se ofrece traducido al castellano. Es veloz en la mayoría de operaciones, pero su código multiplataforma le pasa factura, y no es tan compacto como podríamos esperar. Eso si, trabaja de manera portable por defecto.
Artículos relacionados
Traslado guti.webcindario.com¡La web de D.T.S. activa de nuevo!
100/100 en Acid3
» Leer más, comentarios, etc...
Variable not found
No son una leyenda urbana
Febrero 9th, 2011 - [Enlace local]
Todo el mundo ha oído hablar de ellos… todo el mundo conoce a alguien que los vio una vez… creer en su existencia es a veces sólo cuestión de fe… y sólo algunos privilegiados han podido verlos en persona… Está claro que hablo de los cheques de AdSense, ¿no? :-D
Pues nada, que estoy que no quepo en mí de gozo y quería compartirlo (el gozo, no el cheque ;-D) con todos vosotros, los que hacéis posibles estos milagros. Resulta que hace unos días recibí una carta de Irlanda, en la que venía un regalito como este:

Hace unos cuatro años que coloqué, por probar, AdSense en el blog. Nunca pensé lo grande que sería la alegría que da recibir uno de estos con tu nombre y con una cantidad que jamás soñé que podría conseguir.
Supongo que esto responde a la eterna pregunta “y tú, ¿por qué escribes en tu blog?”:
- Pues por dinero, claro, ¿por qué iba a ser si no?Publicado en: Variable not found.
» Leer más, comentarios, etc...
MadeInFlex
Flash Player 10.2 disponible
Febrero 9th, 2011 - [Enlace local]
Ya tenemos disponible el nuevo Flash Player 10.2 para Windows, Mac y Linux. Ya hablamos un poco en posts anteriores de las mejoras que nos aporta, pero si quereis recordarlas, seguid leyendo.
Resumen de las características
Stage Video
Nos permite un rendimiento mejorado para la reproducción de video. Con esta característica, las webs aprovechan la aceleración por hardware, así Flash Player puede reproducir video de alta calidad gastando muy poca potencia de procesador.
Cursores de mouse nativos
Nos permite el uso de cursores basados en bitmaps en la display list del Adobe Flash Player.
Optimización para IE9
Da soporte a la tecnología de renderización por GPU que nos traerá Internet Explorer 9.
Mejoras en dispositivos mobile
El hecho de mejorar el tratamiento del video usando menos CPU nos aportará una mejor experiencia de usuario, un mejor rendimiento y hará que la vida de la batería del dispositivo sea más durarera. Se ha demostrado que en este aspecto es 34 veces más eficiente que la versión anterior.
Otras características
La reproducción de video es más inmersiva, ya que Flash player 10.2 nos permite pasar a un full screen excelente con un solo click.
Si disponemos de múltiples pantallas, Flash Player 10.2 nos permite cosas como estar viendo un video en full screen en una de las pantallas y en otra seguir trabajando.
Con el soporte a nuevos cursores, tanto estáticos con animados, con una respuesta más afinada, nos permite crear aplicaciones o juegos más enriquecidos.
La nueva caraterística de sub-pixel text rendering mejora la lectura de texto, especialmente en lenguajes con caracteres complejos.
Más información
Para poder probar las características de esta versión, deberemos actualizar la versión del SDK de Flex Hero a la 4.5.0.18623 o superior.
Enlaces de interés
Getting started with stage video
Native mouse cursors in Flash Player 10.2
En este link tenemos la última versión de Flash Player.
Enjoy
» Leer más, comentarios, etc...
programania
TDD: 12 meses 12 katas
Febrero 8th, 2011 - [Enlace local]
A lo largo del camino del coder el cambio (la mejora) es la única constante posible para mantenerse a flote (al menos es así como yo lo entiendo). A lo largo de mi camino como profesional del desarrollo de software he podido experimentar varias revelaciones: la orientación a objetos, la abstracción de acceso a base de datos, el control de versiones, el paradigma MVC, los patrones de diseño, etc. Es una bendición encontrar a excelentes profesionales y fuentes de información que, de vez en cuando, te regalan un descubrimiento de este tipo que cambia radicalmente a mejor tu manera de enfrentarte a nuevos retos.
Mi última revelación se la debo a Luis ya que me ha introducido en la metodología TDD. Aunque ya lo conocía desde hace algunos años, siempre pensé que era algo que solo hacía “esa gente rara y viejuna” que programa en Java. Nunca lo vi como una posibilidad en mi mundo de PHP. No solo estaba equivocado en todo, sino que he podido descubrir que el TDD (y la metodología Agile por extensión) van tremendamente en línea con mi manera de entender el desarrollo de software. Tengo muy claro que es algo en lo que me debo volcar este año para mejorar como desarrollador.
Si a estas alturas aun no sabes en qué consiste la metodología TDD, no te recomiendo que leas sobre ella sino que te pongas manos a la obra y que hagas directamente un ejercicio guiado básico y que veas algún vídeo en Vimeo. Es como mejor se entiende de qué va la película.
Los ejercicios básicos de entrenamiento en TDD se llaman Code Katas y cada una plantea en su enunciado un problema a resolver y una serie de reglas que añaden algo de complejidad al mismo de una manera progresiva. El reto es resolver de una manera adecuada el problema, cumpliendo dichas reglas y llevando a cabo el proceso de TDD que implica escribir los tests primero, provocar un fallo, implementar la corrección del fallo y refactorizar.
Además, para los que disfruten de una mente inquieta, las Katas permiten conocer nuevos lenguajes de programación en el contexto de un problema concreto y guiado bastante más ilustrativo que un HelloWorld.

12 meses 12 katas es una reciente iniciativa española pretende reunir a los TDDistas interesados en mejorar sus habilidades en torno a la realización mensual de una kata. Cada mes proponen una kata distinta y preparan un repositorio en GitHub para que los participantes puedan forkearlo, subir sus soluciones y solicitar un pull desde el repositorio principal. No hay más reglas que las del enunciado de la Kata, por lo que la gente puede implementar sus tests y soluciones en el lenguaje, framework y estrategia de testeo/implementación que les dé la gana, siempre usando TDD o BDD.
Al cabo del mes, el resultado es un excelente repositorio de distintas soluciones a un mismo problema con las que podemos curiosear y aprender mucho. Hay quienes incluso graban (grabamos) un screencast o “katacast” realizando la kata. También ha surgido una buena iniciativa llamada “katabreakers” que consiste en hacer peer review de las katas con la intención de preparar nuevos tests que rompan la implementación, realizar sugerencias o señalar fallos. En definitiva, todo gira en torno a un proceso de aprendizaje de los buenos: en grupo, iterativo e interactivo.
La primera kata correspondiente a enero fue la del StringCalculator y hubo 42 soluciones y 6 katacasts y la de febrero, la de los RomanNumerals, cuenta ya con 16 soluciones y 1 katacast al menos. Se pueden encontrar implementaciones en multitud de idiomas: PHP, Java, Groovy, Ruby, Scala, .net, etc. Nosotros, desde luego, procuraremos mandar nuestra aportación mes a mes al menos en PHP.
Realizar Katas no solo permite profundizar en conocimientos y mejorar la técnica de desarrollo, sino que además permite reconciliarte con la buena programación: la que se basa por encima de todo en las funcionalidad que debe proporcionar nuestro trabajo.
Además, es un total acierto por parte de 12 meses 12 katas haber elegido GitHub como plataforma para todo el intercambio de código fuente y aportaciones ya que nos permite ojear los envíos de código de cada uno, realizar comentarios, vigilar cambios en repositorios y, en definitiva, participar en eso que los propios creadores llaman Social Coding.
Podéis recibir noticias sobre la iniciativa también en twitter siguiendo a @12meses12katas.
A continuación iremos publicando los katacast que vayamos grabando a lo largo del año.
Enero – StringCalculator en PHP5.3
Es el primer katacast que grabo y comento algunos despistes y errores tontos. Es normal si os surge la necesidad imperiosa de asesinarme con lo de las “g” en StringCalculator o el “$expected”. Si vais a mi solución en GitHub podréis ver una versión mucho más refinada, con inyección de dependencias.
Febrero – RomanNumerals en PHP 5.3
A doble velocidad para mayor disfrute y menor desesperación del espectador.
» Leer más, comentarios, etc...
MadeInFlex
Skinning detallado con Flex 4
Febrero 8th, 2011 - [Enlace local]
Uno de los ámbitos fuertes de Spark es el mecanismo de skinning de componentes. Nos ofrece un control total sobre el look and feel de nuestras aplicaciones. En este artículo veremos en profundidad como funciona este aspecto tan importante de Flex 4, acompañado de un proyecto de ejemplo.
Introducción
La nueva arquitectura de skinning que nos ha aportado Flex 4, proporciona una separación clara y precisa entre la lógica y los elementos visuales de un componente. De esta manera se consigue que los componentes en Flex 4 no contengan ninguna información sobre su representación gráfica. Esta información es contenida en el fichero que compone la skin. Mediante FXG y estados, podemos crear skins con mxml únicamente.
Uno de los conceptos más importantes son las skin parts, que nos describen todas las partes de un componente y definen el contrato que el componente establece con la skin. Las skin parts pueden ser dinámicas o estáticas. El tipo de skin part nos determina el tipo de instanciación que tendrá. Además, las skin parts pueden ser requeridas o no.
El proyecto de ejemplo
Es un componente que nos permite seleccionar el sexo y rango de edad de una persona:

Descarga
static y dynamic skin parts
Al crear un componente custom, lo primero que debemos hacer es mirar que partes lo constituirán. En este momento decidimos que partes serán opcionales, cuantas instancias tendremos de cada una de ellas y si se crearán en el inicio de la skin o durante el ciclo de vida de ésta.
Las partes estáticas se crean con la skin y son siempre accesibles. Sólo tendremos una instancia de cada una de estas partes.
Las partes dinámicas se instancian cuando se necesitan.
En el componente definimos las partes que lo comprenden, la lógica específica de la vista y listeners de eventos a los que responde, a parte del control del estado de esta vista y de sus elementos.
En cambio, en la skin determinamos de distribución del layout y los elementos gráficos que la compondrán.
Esta tabla resume las diferencias entre las static y dynamic skin parts (click para maximizar):

Un ejemplo es el siguiente, VSlider, tiene thumb y track como skin parts estáticas debido a que sólo tendremos una instancia y dataTip que es dinámica debido a que su creación será deferida.
Como se resume en la tabla, es adecuado usar una dynamic skin part cuando habrá múltiples instancias de ésta o cuando será instanciada a posteriori y no en el momento de creación de la skin. Son muy útiles cuando en tiempo de compilación no sabemos cuántas instancias vamos a necesitar: por ejemplo, puede ser que tengamos que ir modificando el número de instancias según el valor de una propiedad que modifica el usuario o cuando tenemos que mostrar resultados de una query a la base de datos y no sabemos cuántos resultados nos devolverá.
Trabajar con dynamic skin parts es distinto a hacerlo con static parts, debido sobre todo a que seremos nosotros los encargados de instanciarlas y no el framework.
Declaración de las skin parts en el componente
En nuestro componente de selección de sexo y edad, tenemos los botones de selección de tangos de edad que serán dinámicos. Con el metadata tag [SkinPart] definimos una skin part, tanto dinámica como estática. En el caso de las dinámicas, la variable, en lugar de ser fuertemente tipada, se declara de tipo IFactory, aunque en el parámetro type del tag definimos con el tipo que será instanciada:
Tenemos el parámetro required para especificar si esta skin part es requerida o no, en la mayoría de skin parts dinámicas, required tendrá como valor true.
Definición de las skin parts en la skin
El siguiente paso es la definición de las partes dentro de la skin. Para las static skin parts, directamente ponemos elementos gráficos y otros controles en la skin. Las dynamic skin parts se declaran dentro del tag de Declarations de la skin, debido a que no sabemos cuántas instancias necesitaremos:
Al definir una dynamic skin part debemos declarar el componente dentro del tag Component y este Component debe tener como id el mismo valor que le hemos dado a la skin part dentro de la Clase del componente.
Creación de una instancia de una dynamic skin part
Las dynamic skin parts son declaradas como IFactory. Es por eso que debemos usar el método createDynamicPartInstance() de la clase SkinnableComponent. Este método usa un mecanismo de caching. Aquí vemos un ejemplo de creación:
Vemos que una vez instanciada, la variable tiene que ser casteada para poder ser usada. Además debemos añadirla a la parte del layout que le corresponda, en este caso en el container dropDown.
Control sobre las parts
Tanto para las static como para las dynamic parts, Flex invoca automáticamente el método partAdded(), cada vez que se crea una parte. Es sobrescribiendo este método cuando añadiremos comportamiento específico a cada una de las partes, si es necesario:
Cuando una part se elimina, automáticamente se llama el método partRemoved(). En él deberemos quitar el comportamiento que le habíamos asignado, si es necesario, como, por ejemplo, eliminar event listeners:
Podemos eliminar intencionadamente una parte usando el método removeDynamicPartInstance() .
Para acceder a una dynamic part que hemos creado, tenemos dos maneras:
- Mediante createDynamicPartInstance(skinPart:String)
- Mediante getDynamicPartAt(partName:String, index:int)
Cambio de skin en tiempo de ejecución
Puede interesarnos cambiar la skin de un componente en runtime. Esto implica que debemos guardar el estado de las dynamic parts dentro del código, ya que Flex no se encarga de hacerlo. Es recomendable hacer esto que hemos comentado dentro de los métodos attachSkin() y detachSkin(), ya que estos métodos se llaman cuando la skin se carga y se descarga respectivamente.
¿Código en la skin o en el componente?
En general, la lógica que atañe a la vista, debería estar en la declaración de ésta, es decir, en el componente, pero esta regla no siempre es la más adecuada, depende de los escenarios:
- Si un código de un componente debe ser el mismo independientemente de la skin que se le aplique, vemos claramente que debe estar en el componente.
- Si un código atañe a una determinada representación, este debe estar en la skin.
Sobrescritura de métodos de SkinnableComponent
Todos los componentes visuales de la arquitectura extienden la clase SkinnableComponent. Por lo tanto, heredan sus métodos, propiedades, eventos y demás atributos de esta clase.
Puede ser que para crear una determinado componente custom, debamos sobrescribir métodos como commitProperties(), createChildren(), measure(), updateDisplayList(), attachSkin(), detachSkin(), partAdded(), partRemoved() o getCurrentSkinState().
» Leer más, comentarios, etc...
Variable not found
WebGrid en MVC 3, paso a paso (y II)
Febrero 7th, 2011 - [Enlace local]
Días atrás comentábamos por aquí cómo utilizar el helper WebGrid de MVC 3 para crear rejillas de datos, partiendo de un ejemplo muy sencillo, apenas un par de líneas de código, e introduciendo sucesivas mejoras hasta llegar a un interfaz bastante aceptable para manejar conjuntos de datos con paginación, ordenación, y columnas personalizadas.

Sin embargo, también comentábamos que la pasmosa simplicidad con la que podíamos poner en marcha un grid completo tenía su coste: por defecto, WebGrid necesita disponer de una copia en memoria del conjunto completo de datos sobre el que actúa. Sí, completo :-O.
Es decir, si tenemos un millón de filas de nuestra base de datos y queremos mostrarlas en un orden concreto y por páginas, debemos suministrar a WebGrid una colección con el millón de entidades materializadas en memoria; el helper las ordenará según el criterio activo en ese momento, contará el total de elementos, calculará las páginas necesarias para mostrarlos en función del número de elementos por página definidos, y obtendrá el subconjunto de instancias correspondientes a la página actual. Tras ello, generará el grid y el mecanismo de paginación que podemos ver en su pie.
Obviamente, el impacto en el rendimiento de nuestro sistema puede ser terrible. La materialización de entidades no es un proceso rápido, como tampoco lo es la ordenación en memoria cuando el número de elementos es importante. Y lo peor es que el procedimiento completo se repite para cada petición y usuario conectado, lo que hace que utilizar los mecanismos de paginación y ordenación por defecto no sea una buena idea la mayoría de las veces.
Sin duda es bastante mejor delegar al motor de base de datos las tareas de ordenación y selección de filas, y materializar en memoria sólo las entidades que sean necesarias en la vista actual, es decir, la página de datos visible. ¿Lo hacemos?
1. El Modelo, revisitado
Recordemos que en el post anterior teníamos una clase de servicios del Modelo simplísima, con un único método llamadoObtenerPersonas(), que utilizaba un contexto de objetos de Entity Framework para obtener todas las instancias de la clase Persona almacenadas en la base de datos:public class ModelServices: IDisposable
{
private readonly DatosEntities _datos = new DatosEntities();
public IEnumerable<Persona> ObtenerPersonas()
{
return _datos.Personas.ToList();
}
public void Dispose()
{
_datos.Dispose();
}
}
En este caso, dado que pretendemos delegar al Modelo la responsabilidad de paginar y ordenar adecuadamente los datos antes de enviarlos a WebGrid, necesitamos añadirle dos nuevos métodos: ContarPersonas(), y ObtenerPaginaDePersonas().El primero de ellos,
ContarPersonas(), que retornará el número de elementos totales existentes en la base de datos. Ya hemos comentado antes que WebGrid podía obtener este dato simplemente contando el total de elementos presentes en el origen de datos, pero como ahora pretendemos pasarle sólo los datos de la página actual, esta información debemos indicársela expresamente para que pueda construir el mecanismo de paginación correctamente.El código de este método es bastante simple:
public int ContarPersonas()
{
return _datos.Personas.Count();
}
Vamos ahora a implementar ObtenerPaginaDePersonas(). Como seguro podréis intuir, su objetivo es retornar el conjunto de instancias de Persona que deben aparecer en una página concreta de datos, teniendo en cuenta el número de elementos por página empleado y el criterio de ordenación actual. Asumiendo que estamos utilizando LINQ, la obtención de una página concreta de datos es trivial utilizando los operadores
Skip() y Take(). La única dificultad con la que podemos encontrarnos es la forma de pasar al Modelo el criterio de ordenación actual, pero, como podemos comprobar a continuación hay muchas formas de conseguirlo, casi tantas como desarrolladores que se enfrenten a ella. Para que os hagáis una idea, veremos dos posibilidades: utilizando expresiones de cadena, y basada en expresiones lambda.1.1. ObtenerPaginaDePersonas(), magic string edition
Una posibilidad bastante sencilla de implementar consiste en que el Modelo reciba directamente una cadena de caracteres en la que se encuentre la expresión de ordenación utilizada. Si podemos asegurar, además, que esta cadena venga ya escrita en Entity SQL, simplemente tendríamos que insertar la cláusula de ordenación apropiada:public IEnumerable<Persona>
ObtenerPaginaDePersonas(int paginaActual, int personasPorPagina, string criterioOrdenacion)
{
if (paginaActual<1) paginaActual = 1;
return _datos.Personas
.OrderBy(criterioOrdenacion)
.Skip((paginaActual - 1) * personasPorPagina)
.Take(personasPorPagina)
.ToList();
}
De esta forma, podemos invocar al Modelo pasándole directamente expresiones como “it.Apellidos DESC”, “it.FechaNacimiento ASC”, o incluso combinaciones como “it.Apellidos DESC, it.Nombre DESC”, que funcionarán perfectamente. Observad que la sintaxis debe ser eSQL (de ahí el prefijo “it.” que llevan delante las propiedades del objeto actual).Este enfoque, aunque bastante sencillo y rápido de implementar tiene algunas contraindicaciones. El hecho de escribir estas expresiones en el interior de cadenas de texto hace que éstas sean inmunes a refactorizaciones o comprobaciones en tiempo de compilación, lo que aumenta la probabilidad de aparición de errores difíciles de detectar. Asimismo, estamos confiando ciegamente en que la expresión es eSQL sintáctica y semánticamente correcto, por lo que o bien nos arriesgamos a que reviente en tiempo de ejecución si no introducimos las comprobaciones oportunas, o bien debemos delegar a otro componente (por ejemplo, al Controlador) la responsabilidad de construir siempre expresiones válidas.
1.2. ObtenerPaginaDePersonas(), lambda edition
Si queremos evitar el envío de información en cadenas de texto, podemos seguir el enfoque propuesto por LINQ y utilizar árboles de expresión para trasladar los criterios de ordenación al Modelo.En este caso, el método del Modelo recibirá, además de la página actual y el número de filas por página, un árbol de expresión que contiene la expresión de ordenación, y un elemento de la enumeración
Direccion indicando si debe ordenarse ascendente o descendentemente. El código podría ser como el siguiente:public IEnumerable<Persona> ObtenerPaginaDePersonas<T>(
int paginaActual, int personasPorPagina,
Expression<Func<Persona,T>> ordenacion,
Direccion direccion)
{
if (paginaActual<1) paginaActual = 1;
IQueryable<Persona> query = _datos.Personas;
if (direccion == Direccion.Ascendente)
query = query.OrderBy(ordenacion);
else
query = query.OrderByDescending(ordenacion);
return query.Skip((paginaActual - 1) * personasPorPagina)
.Take(personasPorPagina)
.ToList();
}
Como se puede observar, se trata de un método genérico para dar cobertura a los distintos tipos de propiedad por los que es posible ordenar, que es el tipo de retorno del árbol de expresión ordenacion.También se puede ver que se aprovecha de la ejecución diferida de LINQ to SQL para ir especificando de forma sucesiva las distintas cláusulas de la consulta. Ésta no será ejecutada hasta el final, en la llamada al método
ToList(), que es cuando realmente se materializarán las instancias de Persona presentes en la página de datos actual.De esta forma, conseguimos que desde el Controlador podamos obtener la página de datos, por ejemplo, así:
var personas = _services.ObtenerPaginaDePersonas(
page,
personasPorPagina,
p=>p.NumeroDeHijos, // Expresión ordenación
Direccion.Descendente // Ascendente);
Observad que, a diferencia de la técnica que vimos anteriormente, aquí sí que usamos tipado fuerte para indicar la ordenación. Un cambio de nombre de la propiedad NumeroDeHijos, por ejemplo, sería refactorizada correctamente o, cuanto menos, generaría un error en compilación.Como principal inconveniente, decir que no es tan potente y flexible como la anterior. Por ejemplo, en este caso no podemos indicar de forma inmediata más de una propiedad de ordenación, cosa que antes sí era muy sencillo. Eso sí, en nuestro escenario, dado que vamos a ordenar según columnas independientes del grid, tampoco este aspecto es demasiado importante.
En definitiva, existen gran cantidad de posibilidades para implementar el método del Modelo que retorna las instancias pertenecientes a una página concreta de datos atendiendo a los criterios de ordenación especificados. Aquí hemos visto un par de ellas, pero basta con pararse a pensarlo un rato y fácilmente podremos idear un buen puñado más de soluciones.
Vamos a pasar a estudiar ahora qué cambios debemos realizar en el Controlador para realizar la paginación correcta.
2. El Controlador
Si habéis descargado el ejemplo del post anterior u os habéis peleado un poco con WebGrid, habréis notado que el mantenimiento del estado de la rejilla se realiza propagando entre llamadas una serie de parámetros en el query string que, por defecto, son los siguientes:
- page, que indica el número de página actual,
- sort, la columna por la que estamos ordenando,
- sortDir, la dirección de ordenación actual, indicada con las constantes “ASC” o “DESC”.
public ActionResult Index(int page = 1, string sort = "Apellidos", string sortDir = "ASC")
{
// Obtener el número total de personas
// Obtener la colección de personas de la página actual
// Retornar la vista suministrándole esos datos
}
Observad el uso de parámetros opcionales para la acción, en los que especificamos un valor por defecto para cuando no estén indicados de forma explícita en la petición.Ya en el cuerpo del método, la obtención del número de personas es inmediata gracias al método
ContarPersonas() que hemos creado anteriormente en el Modelo. La obtención de las personas para poblar la rejilla depende del enfoque utilizado en la implementación del método ObtenerPaginaDePersonas(). A continuación veremos algunas posibilidades, aunque antes vamos a pararnos en otro detalle.A diferencia del ejemplo del post anterior, en el que la Vista sólo necesitaba una lista de personas para maquetarse, en esta ocasión debemos suministrarle alguna información más:
- el número de personas por página,
- la colección de personas, aunque sólo las presentes en la página actual,
- el número total de personas, para que WebGrid pueda crear la herramienta de navegación por páginas.
public class PaginaDePersonasViewModel
{
public int NumeroDePersonas { get; set; }
public IEnumerable<Persona> Personas { get; set; }
public int PersonasPorPagina { get; set; }
}
De esta forma, podemos ir ya dando forma al cuerpo de la acción, que quedaría de la siguiente manera:public ActionResult Index(int page = 1, string sort = "Apellidos", string sortDir = "ASC")
{
const int personasPorPagina = 10;
var numPersonas = _services.ContarPersonas(); var personas = ... // Obtener la colección de personas
var datos = new PaginaDePersonasViewModel()
{
NumeroDePersonas = numPersonas,
PersonasPorPagina = filasPorPagina,
Personas = personas
};
return View(datos);
}
Como comentábamos anteriormente, la obtención de las personas a mostrar en la página actual dependerá de la implementación del Modelo. Veremos algunas posibilidades.Una solución muy simple aunque bastante cándida e inocentona, basada en la primera de las implementaciones del Modelo que hemos visto anteriormente, podría ser la siguiente:
var personas = _services.ObtenerPaginaDePersonas(
page,
personasPorPagina,
"it." + sort + " " + sortDir
);
Como podemos observar, construimos directamente la expresión de ordenación en Entity SQL basándonos en los parámetros recibidos en el query string. Obviamente, y dado que estos parámetros son fácilmente manipulables, un nombre de columna incorrecta o una dirección distinta de “ASC” o “DESC” provocarían una excepción en tiempo de ejecución:
Este error es fácil de evitar simplemente introduciendo código que compruebe estos parámetros y establezca valores por defecto en caso de existir algún problema, como el mostrado a continuación, donde comprobamos que la columna de ordenación se encuentra en una “lista blanca” de columnas permitidas, y que la ordenación es ascendente o descendente:
...
sortDir = sortDir.Equals("desc", StringComparison.CurrentCultureIgnoreCase) ? sortDir : "asc";
var validColumns = new[] { "apellidos", "fechanacimiento", "email", "numerodehijos" };
if (!validColumns.Any(c => c.Equals(sort, StringComparison.CurrentCultureIgnoreCase)))
sort = "apellidos";
var personas = _services.ObtenerPaginaDePersonas(
page,
personasPorPagina,
"it." + sort + " " + sortDir
);
...
Si en cambio preferimos utilizar en el Modelo la opción que vimos anteriormente basada en el uso de árboles de expresión, también podemos crear un código que suministre los criterios de ordenación en función de la columna y dirección actual:IEnumerable<Persona> personas;
Direccion dir = sortDir.Equals("ASC", StringComparison.CurrentCultureIgnoreCase) ?
Direccion.Ascendente:
Direccion.Descendente;
switch(sort.ToLower())
{
case "fechanacimiento":
personas = _services.ObtenerPaginaDePersonas(page, personasPorPagina, p => p.FechaNacimiento, dir);
break;
case "numerodehijos":
personas = _services.ObtenerPaginaDePersonas(page, personasPorPagina, p => p.NumeroDeHijos, dir);
break;
case "email":
personas = _services.ObtenerPaginaDePersonas(page, personasPorPagina, p => p.EMail, dir);
break;
case "apellidos":
personas = _services.ObtenerPaginaDePersonas(page, personasPorPagina, p => p.Apellidos, dir);
break;
default:
personas = _services.ObtenerPaginaDePersonas(page, personasPorPagina, p => p.Apellidos, dir);
break;
}
En el proyecto que podréis descargar desde el enlace disponible al final del post, encontraréis ambas implementaciones completas.Antes de pasar a la Vista, veamos el código completo del controlador pasando los criterios de ordenación al Modelo mediante cadenas. Exceptuando las líneas introducidas para mejorar la legibilidad del código, apenas llegamos a la docena de líneas para completar la acción:
public class Demo2Controller : Controller
{
private ModelServices _services = new ModelServices();
public ActionResult Index(int page = 1, string sort = "Apellidos", string sortDir = "ASC")
{
const int personasPorPagina = 10;
var numPersonas = _services.ContarPersonas();
sortDir = sortDir.Equals("desc", StringComparison.CurrentCultureIgnoreCase) ? sortDir : "asc";
var validColumns = new[] { "apellidos", "fechanacimiento", "email", "numerodehijos" };
if (!validColumns.Any(c => c.Equals(sort, StringComparison.CurrentCultureIgnoreCase)))
sort = "apellidos";
var personas = _services.ObtenerPaginaDePersonas(
page,
personasPorPagina,
"it." + sort + " " + sortDir
);
var datos = new PaginaDePersonasViewModel()
{
NumeroDePersonas = numPersonas,
PersonasPorPagina = personasPorPagina,
Personas = personas
};
return View(datos);
}
}
3. La Vista
La mayor parte de la Vista que implementamos en el post anterior sigue siendo válida, sólo tendremos que retocarle un par de detalles que encontramos en las primeras cuatro líneas.@model WebGridDemo.ViewModels.PaginaDePersonasViewModel
@{
ViewBag.Title = "Personas";
WebGrid grid = new WebGrid(rowsPerPage: Model.PersonasPorPagina);
grid.Bind(Model.Personas, autoSortAndPage: false, rowCount: Model.NumeroDePersonas); }
En la primera línea, en la directiva @model debemos definir el tipo de datos recibidos desde el Controlador, que como ya hemos visto, en este caso se trata de una instancia de PaginaDePersonasViewModel que contiene toda la información que necesita la Vista para maquetarse apropiadamente.A continuación, tras establecer el título de la página, instanciamos el WebGrid suministrándole a su constructor el valor del parámetro
rowsPerPage, el número de filas por página que estamos utilizando, que es el mismo usado por el Controlador a la hora de solicitar los datos al Modelo.Finalmente, invocamos a su método
Bind(), donde podemos indicamos:- el conjunto de Personas a mostrar en la página actual,
- que no deseamos utilizar la ordenación y paginación automática, estableciendo
autoSortAndPageafalse, - mediante el parámetro
rowCount, el número total de personas almacenadas en la base de datos.
4. Y recapitulando…
A lo largo de este post hemos vuelto a recorrer el Modelo, Controlador y Vista que ya implementamos hace unos días, comentando los cambios que tenemos que hacer para conseguir una paginación de datos más eficiente.Hemos visto distintas alternativas para implementar el Modelo, basadas en Entity Framework. No son las únicas posibilidades ni mucho menos, pero espero al menos que os den ideas para implementar vuestras propias soluciones. También hemos reescrito el Controlador, implementando el consumo de estos servicios del Modelo para obtener justo la información que necesitamos para mostrar una página de datos, y la hemos pasado a la Vista, a la que hemos tenido que hacer sólo ligeras modificaciones.
Finalmente, como el post ha quedado algo extenso, repasamos rápidamente qué es necesario hacer para implementar un WebGrid con una paginación eficiente:
- En el Modelo:
- Necesitamos un mecanismo para obtener el número total de elementos.
- Asimismo, tendremos que crear un método para obtener los elementos pertenecientes a una página concreta, atendiendo a los criterios de ordenación suministrados.
- En el Controlador:
- Debemos capturar los parámetros
page,sortysortDirde la petición, a través de los cuales podremos conocer la página a mostrar, la columna y dirección de ordenación, respectivamente. - Obtener desde el Modelo el número total de elementos, así como el conjunto de instancias pertenecientes a la página actual de datos, según los criterios de ordenación actuales.
- Retornar la vista, suministrándole:
- Los datos a mostrar.
- El total de elementos.
- El número de elementos por página que estamos usando
- En la Vista:
- Indicar, al instanciar el WebGrid, el número de elementos por página (dato enviado desde el Controlador).
- Enlazar en WebGrid a la colección suministrada por el Controlador, desactivando la paginación y ordenación automática, e indicándole el total de elementos disponibles.

Como en otras ocasiones, podéis descargar el proyecto desde SkyDrive (requiere VS2010, SQL Express y ASP.NET MVC 3). ¡Que aproveche! ;-)
Publicado en: Variable not found.
» Leer más, comentarios, etc...
Variable not found
Enlaces interesantes 29
Febrero 6th, 2011 - [Enlace local]
Estos son los enlaces publicados en Variable not found en Facebook y Twitter desde el domingo, 30 de enero de 2011 hasta el domingo, 06 de febrero de 2011.
Espero que te resulten interesantes. :-)
- Elijah Manor: "Convention-Based Templating in MVC 3" by Jaco Pretorius
Fecha: 02/02/2011 - Elijah Manor: "Make It Yours" by K. Scott Allen
Fecha: 02/02/2011 - David Ebbo: Just released T4MVC 2.6.42 that supports partial helpers for Razor view. It's on Nuget.
Fecha: 02/02/2011 - David Noël_hayden: Blogged: IDependencyResolver in ASP.NET MVC 3 #aspnet ASP.NET MVC
Fecha: 02/02/2011 - ReSharper 5.1.3 Released. Fix for VS Intellisense
Fecha: 02/02/2011 - Eduard Tomàs: [BlogPost] Detalles del webcast de mañana sobre ASP.NET MVC 3: ;-)
Fecha: 02/02/2011 - Elijah Manor: "Spark View Engine v1.5 Released for MVC2 & MVC3
Fecha: 01/02/2011 - Elijah Manor: "MVC 3 AdditionalMetadata Attribute w/ ViewBag to Render Dynamic UI" by Steve Michelotti
Fecha: 31/01/2011 - Complexity in ASP.NET MVC, Part 2
Fecha: 31/01/2011 - Phil Haack: RouteMagic. A library of useful routing helpers available on NuGet and source in CodePlex.
Fecha: 31/01/2011
Publicado en: Variable not found
» Leer más, comentarios, etc...
Mal Código
Nuevo Videojuego Publicado
Febrero 5th, 2011 - [Enlace local]
Llevaba mucho tiempo sin escribir en el blog, pero uno de los proyectos en los que he estado últimamente merecía toda mi atención. Y el resultado es este:Cell & Love en AndroidUn juego de Mutant-Games, del que ya tenían versión en iPhone, y del que yo solo me he encargado de transformar a un juego de Android. Usando todo el arte anterior y con la ayuda de la librería andEngine:En próximos posts
» Leer más, comentarios, etc...
Picando Código
Debian 6 estable – Squeeze
Febrero 5th, 2011 - [Enlace local]
Como se anunciara en las noticias del proyecto, Debian 6 Squeeze será lanzado este fin de semana. Con motivo de este lanzamiento, se organizaron fiestas en varios lugares del mundo, incluyendo muchos países de habla hispana: Argentina, Bolivia, Chile, Colombia, Costa Rica, El Salvador, España, México, Paraguay y Venezuela. Brasil con su fuerte comunidad de software libre obviamente participa también, con varias fiestas a lo largo del país.
Los detalles momento a momento del lanzamiento se pueden seguir por la cuenta de Debian en Identi.ca.
Repasemos un poco la historia de esta versión de Debian, precedida por Lenny, y sucedida por Wheezy.
- 01-09-2008 : Se anuncia el nombre clave de la distribución. (En español)
- 29-07-2009 : Debian decide adoptar congelamientos de código basados en intervalos de tiempo ver anuncio. (En español)
- 18-10-2009 : El congelamiento de desarrollo debería ser para Marzo de 2010, ver anuncio.
- 2010-02-08 : El equipo de lanzamiento anuncia que un congelamiento en marzo es poco probable, ver anuncio.
- 2010-08-06 : Se congela Debian testing, ver anuncio.
En el medio también se fueron anunciando distintas características de la nueva versión de la distribución.
Arquitecturas
En este lanzamiento se descarta el soporte para HP PA-RISC (‘hppa’), Alpha (‘alpha’) y ARM (‘arm’). Las arquitecturas oficiales son entonces:
- 32-bit PC (‘i386′)
- SPARC (‘sparc’)
- PowerPC (‘powerpc’)
- MIPS (‘mips’ (big-endian) y ‘mipsel’ (little-endian))
- Intel Itanium (‘ia64′)
- S/390 (‘s390′)
- 64-bit PC (‘amd64′)
- ARM EABI (‘armel’)
Además, una de las novedades es que se agregan en esta versión ports GNU/kFreeBSD (‘kfreebsd-amd64′ y ‘kfreebsd-i386′) como vistazo previo de tecnología. Estos ports son los primeros incluidos en un lanzamiento de Debian que no están basados en el kernel Linux. Usan el kernel FreeBSD con un entorno de usuario GNU.
Los desarrolladores previenen que los ports todavía se están poniendo al día con la destacada alta calidad de los ports de Linux, y algunas características avanzadas del escritorio no están disponibles todavía. De todas formas, el soporte de software común de servidores es fuerte y extiende las características de versiones de Debian basadas en Linux con las características únicas conocidas del mundo BSD. Esta es la primera vez que una distribución Linux ha sido extendida para permitir también el uso de un kernel no-Linux.
Debian viene trabajando en versiones alternativas desde hace mucho tiempo. Podemos ver en su página de ports que además de un kernel FreeBSD, existen versiones para Hurd y NetBSD.
Software
Como con cada versión nueva de Debian, hay una disponibilidad mayor de paquetes de software. Con Squeeze la distribución incluye más de 10.352 paquetes nuevos, para un total de más de 29.050 paquetes. 15.436 paquetes han sido actualizados y se han eliminado 4.238 paquetes por varias razones. No habrán más actualizaciones para estos paquetes y serán marcados ‘obsolete’ en los front-end de gestión de paquetes.
X.Org 7.3 se actualiza a X.Org 7.5. Los entornos de escritorio se incluyen en las siguientes versiones: GNOME 2.30, KDE 4.4.5, Xfce 4.6.2 y LXDE 0.5.0. Se incluye OpenOffice.org 3.2.1, KOffice 2.2.1, GNUcash 2.2.9, GNUmeric 1.10.8 y Abiword 2.8.2. En el área de internet, se incluye Evolution 2.30.3, Pidgin 2.7.3.
La suite Mozilla también fue actualizada. En este sentido, no entiendo porqué Debian sigue esforzándose en continuar el desarrollo del pobre Iceweasel. Esta versión incluye iceweasel 3.5.15. Firefox va por la versión 3.6.13, a punto de sacar su versión 4, que los usuarios de Debian seguramente no verán por un buen tiempo. El proyecto GNU Icecat se mantiene a la par del desarrollo de Firefox, por lo que no habría problemas por el uso de la marca. Sería interesante ver una colaboración entre estos dos proyectos, para acelerar el desarrollo de Iceweasel… En fin, Squeeze también incluye icedove 3.0.7.
La distribución se hace disponible en binarios en 4 a 5 DVDs o 28 a 32 CD’s (dependiendo de la arquitectura) y el código fuente en 4 DVDs o 28 CDs. También existe un DVD multi-arch, con parte del lanzamiento en amd64 e i386 junto al código fuente. También existe una imagen Blu-ray para las arquitecturas amd64 e i386.
Kernel Linux liberado
Squeeze viene con Linux 2.6.32. A partir de este lanzamiento, el kernel Linux distribuido con Debian estará libre de blobs de firmware no libres. Éstos han sido movidos a paquetes separados en la sección no-libre del archivo Debian. Debian tiene un compromiso con el software libre a través de su contrato social que incluye las directrices de software libre de Debian. Y digamos que incluir estos blobs no-libres en la distribución oficial no coincidía con este contrato.
Respecto a este tema, es interesante la publicación de Alexander Reichle-Schmehl, desarrollador de Debian, Myths and Facts about Firmwares and their non-removal from Debian. En él hace algunas aclaraciones que son importantes en el aspecto de la liberación del kernel. Primero, el cambio afecta únicamente a este lanzamiento, los kernels anteriores se mantendrán intactos. Lo que se hizo fue mover los paquetes de firmware de su archivo principal a non-free.
Estos archivos aún estarán disponibles al momento de instalación descargándolos previamente o durante la instalación. Son firmware para drivers de dispositivos, por lo que no todos quieren tenerlos. Al entregar estos paquetes de manera separada, aquellos que quieran usar firmware no-libre podrán hacerlo, y quienes no quieran tenerlos, pueden no instalarlos y listo.
Alexander comenta un poco más en el tema de la filosofía del software libre. Explica que este objetivo se alcanzó con la ayuda de muchos desarrolladores del kernel Linux, y no son la única distro interesada en crear un linux libre. Cita a Fedora y supone que Debian fue una de las primeras grandes distribuciones en darse cuenta del problema. De todas formas hay que agregar que ya existen varias distribuciones y proyectos que apuntan a tener un sistema operativo 100% libre.
La Free Software Foundation sigue considerando que Debian no es una distro libre. Si bien reconoce este nuevo hito como un paso adelante hacia una distro libre, no la considera libre por la disponibilidad de software privativo por medio de su repositorio no libre.
Haciendo hincapié en el tema del firmware privativo, repito un comentario publicado en el post de Alexander Reichle-Schmehl que a su vez es una cita de un desarrollador en Fedora:
Actualizado firmware qlogic 2400 y 2500 a 5.03.13. ¿Qué hace 5.03.13? Nadie sabe, excepto QLogic, y no lo van a decir. Les pregunté, y me dijero que la información estaba disponible únicamente mediante NDA (acuerdo de confidencialidad). Así que, los aliento a imaginarse qué hace este firmware, y los bugs que arregla. Mientras están en eso, imaginen un mundo donde los fabricantes liberan el código fuente de su firmware.
Debian Live
Otra novedad es que a partir de Squeeze, Debian provee sistemas Live oficiales para amd64 e i386. Las imágenes live se crean con live-build, una herramienta para crear imágenes live personalizadas. Más info en http://live.debian.net/.
Debian Wheezy
Para aquellos que usamos Debian Testing, el lanzamiento de Squeeze implica que comienza el desarrollo de una nueva versión testing. Por ahora el desarrollo está congelado hasta llegar a la versión estable. Así que dentro de un tiempo empezaremos a ver las actualizaciones “grandes” en nuestros sistemas testing. Vengo usando Debian testing en mi laptop desde hace un buen tiempo. Varias veces amagué a formatear e instalar ArchLinux como en mi computadora de escritorio.
Pero todavía le tengo cariño a Debian, y mi laptop está funcionando demasiado bien. Así que no tengo razones para sacar Debian e instalar otra distribución. Como comenté en posts anteriores, vengo usando también Ubuntu en mi computadora de trabajo. Así que no me salvo de Debian.
Mucho éxito para Debian y a aquellos que organizaron fiestas de lanzamiento que se diviertan mucho hoy, tomen cerveza Debian, y disfruten de una versión más de Debian
» Leer más, comentarios, etc...
Bitácora de Javier Gutiérrez Chamorro (Guti)
Activar o desactivar bloqueo numérico
Febrero 5th, 2011 - [Enlace local]
Como os comenté en Packard Bell EasyNote LM86-JN-380SP, hay casos en los que por comodidad nos interesa que Windows arranque activando o desactivando el bloqueo numérico (NumLock/NumLck/BloqNum) o bloqueo desplazamiento (ScrollLock/ScrLck/BloqDes). Anteriormente esta tarea era trivial, ya que la mayoría de BIOS nos permitían configurar el valor por defecto. Ahora no lo es, pero sigue [...]Artículos relacionados:
» Leer más, comentarios, etc...
Picando Código
5 tipos de programadores
Febrero 5th, 2011 - [Enlace local]
Otra lista sobre los “tipos de programadores“. Ya en los principios del blog comenté al respecto, traduciendo parte del artículo de Jeff Atwood sobre los dos tipos de programador. También publiqué un webcomic con los tipos de programadores, que incluye una lista bastante extensa. Y si buscan, hay muchas listas más en internet sobre el tema, agrupando a los programadores en distintos grupos…
En esta ocasión se trata de una lista que tiene ya unos meses, algunos tal vez ya la hayan leído, pero surgió nuevamente en Reddit recientemente. El autor es Steven Benner y su post: The 5 types of programmer (licencia CC).
Programador cinta pato
Puede que el código no sea lindo, pero maldición, ¡funciona!
Este tipo es la base de tu empresa. Cuando algo falla, él lo arreglará rápido y de manera que no volverá a romperse. Por supuesto no le importa cómo se vea, la facilidad de uso, ni ningún otra de esas preocupaciones triviales, pero lo hará pasar, sin mucha chara o tonterías que hagan perder el tiempo. La mejor forma de usar esta persona es apuntarlo a un problema y alejarse.
Creo que todos en algún momento asumimos el rol del programador “cinta pato”. Cuando subimos algo a producción, y nos acordamos a último momento de algo, o un usuario nos reporta un bug, generalmente entramos en el modo “cinta pato”, y lo importante es ir y solucionar el problema. Ya habrá tiempo de mejorarlo más tarde (ese “más tarde” raras veces llega…), pero cuando el tiempo juega en contra, no queda otra opción que simplemente arreglar lo que está roto.
Programador perfeccionista obsesivo compulsivo
¿Que le querés hacer qué a mi código?
Es el tipo al que no le importan las fechas límite o presupuestos, eso es insignificante cuando se compara con la forma de arte que es la programación. Cuando finalmente recibes el producto terminado no tendrás otra opción que someterte a la impresionante gloria y radiante belleza del código perfectamente formateado, no, perfectamente bello, que es tan eficiente que cualquier cosa que quisieras hacerle no haría más que difamar una obra maestra. Es el único calificado para trabajar en su código.
Entiendo que existan programadores así, pero me suena a pedante. Sí está bien considerar un arte el código, y estar conforme con el código que uno escribió siguiendo buenas prácticas y demás. Pero creo que el desorden obsesivo compulsivo puede traer más problemas que soluciones. De todas formas en el mercado laboral las fechas límite y presupuestos, por más que odiemos escuchar sobre ellas, generalmente tienen peso en el desarrollo.
Programador anti-programación
Soy un programador, maldición. Yo no escribo código.
Su mundo tiene una simple verdad; escribir código es malo. Si tienes que escribir algo entonces lo estás haciendo mal. Alguien más ya ha hecho el trabajo así que simplemente utiliza su código. Te dirá cuánto mas rápida es su práctica de desarrollo, aunque le lleva tanto tiempo o más que a los demás programadores. Pero cuando obtengas el proyecto serán solo 20 líneas de código actual y será muy fácil de leer. Puede no ser muy rápido, eficiente, o compatible hacia adelante, pero estará hecho con el menor esfuerzo requerido.
Es un perfil que trataría de evitar. Pero no siempre, sí al extremo como se describe en este caso. Pero muchas veces reinventar la rueda nos complica y demora el desarrollo, y puede haber algún framework que nos facilite la tarea. De todas formas está el extremo de los que usan un framework para TODO, y al final el programa es puro código espagueti de configuraciones que intentan integrar framework mas framework, y el producto final termina siendo un bloatware enorme, sin quien logre entender lo que hace sin tener que estudiar 30 frameworks antes.
Programador a medias
¿Qué quieres? Funciona, ¿no?
El tipo al que no podría importarle menos la calidad, eso es trabajo de otra persona. Logra las tareas que le piden hacer, rápido. Puede no gustarte su trabajo, los otros programadores lo odian, pero la gerencia y los clientes lo aman. Por más dolor que te cause en el futuro, él sin ayuda es quien mantiene las fechas límites así que no puedes burlarte (no importa cuánto quieras hacerlo).
Conozco a algún programador de este tipo. Casualmente, tiene matices del programador “perfeccionista”, pero no por buenas prácticas, sino por el hecho de que deja funcionando las cosas, y eso está perfecto, pronto. Cuando tengas que mantener su código o arreglar algo que hizo, vas a acordarte de su familia entera… pero hay varios así.
Programador teórico
Bueno, eso es una posibilidad, pero en la práctica esto puede ser una alternativa mejor.
Este tipo está mas interesado en las opiniones que en lo que se debería hacer. Pasará el 80% del tiempo mirando en blanco su computadora pensando maneras de lograr una tarea, 15% de su tiempo quejándose de fechas límite irrazonables, 4% de su tiempo refinando las opciones, y 1% de su tiempo escribiendo código. Cuando recibas el trabajo final siempre será acompañado por la frase “Si tuviera más tiempo podría haber hecho esto de la manera correcta”.
Caigo un poco en este perfil también. Cuando encuentro una solución puedo darle muchas vueltas y “perder” mucho tiempo cuestionándome si la solución es la más perfecta. A veces puedo pasar tiempo ideando distintas soluciones y generalmente no llego a algo que me paresca “perfecto”, sino “suficientemente bueno”. Pero creo que eso es parte del supuesto que me queda muchísimo por aprender todavía, y siempre va a haber una “forma mejor de hacer las cosas” por aprender.
Tengo que admitir que últimamente he estado haciendo más que nada “cinta pato”. Mucho del trabajo que he hecho recientemente consiste más que nada en corregir errores y agregar pequeñas características a alguna funcionalidad ya hecha. Pero a su vez, al arreglar algo, ya encuentro algún código que puedo refactorizar o corregir, y generalmente caigo en la “pérdida de tiempo” del programador teórico. De todas formas al entrar en el loop “teórico”, tengo una condición de salida con uno de los programadores del equipo que insiste con “esto es suficientemente bueno para ahora, si volvemos a usarlo, lo mejoraremos más adelante”.
Creo que la mayoría tenemos distintas características de cada uno de estos 5, y probablemente falten un montón más (basta con ver el webcomic). En fin, una lista más para la lista de listas… ¿Y ustedes en qué perfiles estarían?
Comparte:
» Leer más, comentarios, etc...
Picando Código
Aprender Ruby con Ruby Koans
Febrero 4th, 2011 - [Enlace local]
Si bien abandoné los posts teóricos sobre Ruby esta semana, descubrí algo increíble para estudiar más el lenguaje de manera didáctica. En un correo de la lista de Rubysur se comentó del grupo de estudio que se formó para aprender Ruby en Montevideo (interesados escribir a la lista de correo). Decía que habían comenzado con los Ruby Koans.
¿Qué es un koan? Definición de Wikipedia:
Un k?an (??; Japonés: k?an, Chino: g?ng’àn) es, en la tradición zen, un problema que el maestro plantea al novicio para comprobar sus progresos. Muchas veces el ‘k?an parece un problema absurdo, ilógico o banal. Para resolverlo el novicio debe desligarse del pensamiento racional y aumentar su nivel de conciencia para adivinar lo que en realidad le está preguntando el maestro, que trasciende al sentido literal de las palabras.
Así se plantea el aprendizaje en este sitio de Ruby Koans:
Los Koans te llevan por el camino a la iluminación para aprender Ruby. La meta es aprender el lenguaje Ruby, la sintaxis, estructura y algunas funciones y bibliotecas comunes. También te enseñamos la cultura. El testing no es solo algo que apoyamos sin un respaldo, sino algo que vivimos. Es esencial en tu búsqueda que aprendas y hagas cosas grandes con el lenguaje.
Y realmente hacen hincapié en el desarrollo guiado por pruebas (TDD), ya que estamos obligados a realizar los ejercicios mediante testing. Para comenzar a hacer los ejercicios, debemos descargar el archivo zip con el código de los koans. Una vez descomprimidos, ejecutamos:
[fernando@hoth koans]$ ruby path_to_enlightenment.rb
De esta manera se nos irá presentando la palabra del “maestro zen”, que nos irá indicando qué archivo debemos editar, y dónde se encuentran los errores. Además, veremos una barra de progreso hasta 274. La idea es que modifiquemos los test para que pasen, reflexionemos sobre qué nos está enseñando cada test, y por último mejorar el código (refactorizar).
En fin, recién comencé con esto, pero lo encuentro sumamente útil, dinámico y una manera muy original de aprender Ruby. También es un acercamiento interesante a TDD. Así que aprovecho para compartirlo con aquellos que estén siguiendo conmigo el camino hacia la iluminación en Ruby…
Comparte:













