viernes, 24 de diciembre de 2010

Sudo navideño

Genial tira de xkcd


Y recordad: un gran poder implica una gran responsabilidad.

domingo, 11 de julio de 2010

GWT o como facilitar la vida al programador de Javascript

Buenos días a todos, me dispongo a escribir esta entrada escuchando el nuevo de Kylie Minoge (Aphrodite) del que me gusta especialmente esta canción:
Y sin más dilación entraré a tratar en el tema que me ha traido hoy con vosotros, Google Web Toolkit, GWT a partir de ahora. Como muchos de vosotros sabréis, o quizá no tantos, este producto de Google es una herramienta que facilita/abstrae al programador web del tedioso mantenimiento del Javascript, pues cuando no se usa un buen framework para el desarrollo de Javascript, como Joose, del que nos habló Javi hace tiempo, que permite realizar programación orientada a objetos en Javascript resulta dificilisimo encontrar errores y mantener ese código. Cito directamente de la página de introducción del GWT, que aunque sea de la versión 1.7 sirve para resumir lo que quiero decir:
Actualmente, la creación de aplicaciones web resulta un proceso pesado y propenso a errores. Los desarrolladores pueden pasar el 90% de su tiempo estudiando las peculiaridades de los navegadores. Por otra parte, la creación, la reutilización y el mantenimiento de una gran cantidad de componentes AJAX y bases de código JavaScript pueden ser tareas complejas y delicadas. Google Web Toolkit (GWT), especialmente en combinación con el complemento de Google para Eclipse, facilita estas arduas tareas al ofrecer a los desarrolladores la posibilidad de crear y mantener rápidamente aplicaciones JavaScript con interfaces complejas, pero de gran rendimiento, en el lenguaje de programación Java.
Aunque a mi me parece que el 90% del tiempo en entender las particularidades de cada navegador me parece una super exageración, si es verdad que los componentes en cada navegador funcionan de una forma distinta, permitiendo GWT abstraernos de estos detalles.Además facilita el desarrollo de la progración con AJAX.
Si a alguien le ha resultado interesante este componente y quiere ponerse manos a la obra tan solo tiene que empezar por esta pequeña introducción en la que los chicos de Google nos cuentan como empezar a trabajar con esta herramienta, como se integra con eclipse y otros aspectos fundamentales de la configuración. Aunque en la página anterior no venga como integrarlo con Netbeans, en el propio blog de google tienen una entrada contando como realizar una aplicación GWT en este entorno de desarrollo.
Una vez terminados estos pasos, es recomendable ver el tutorial que explica como hacer la primera aplicación Web. Otra de las ventajas que tiene usar GWT es que permite el uso de JUnit como framework para realizar las pruebas unitarias, y como todos sabemos es una herramienta indispensable. Aquí he encontrado como integrar GWT con JUnit.
Poco más que decir de este framework que se ha convertido en mi herramienta de trabajo en estos meses que llevo ya trabajando en Qwi. Solo me queda por decir que de vez en cuando se echa de menos programar tu propio Javascript aunque gracias a JSNI se puede introducir el código javascript queramos. Por otro lado hay veces que me gustaría poder moldear a mi gusto las estructuras HTML que genera, pues hay veces que crea estructuras que no son necesarias para lo que queremos construir en un momento dado. Es verdad que con GWT con UiBinder que permite definir la estructura de la página en un xml y luego en la clase java asociada tratar los elementos que hemos definido, por decirlo de alguna manera, dinámicos, es relativamente fácil controlar las estructuras generadas.

miércoles, 9 de junio de 2010

ManyToMany en Hibernate con anotaciones

Muy buenas a todos, ya se que me echabais de menos, así que he decicido volver a escribir por aquí. En esta ocasión os voy a contar como representar con Hiberante una tabla Many To Many, pues ha sido una de las cosas que más me han dado la lata en el nuevo curro.
Para entrar en situación voy a exponer un pequeño ejemplo con el que todos los labos y ex-labos estaremos familiarizados:
Supongamos que por una extraña razón a Geno se le juntan muchos marrones encima (cosa que no pasa casi nunca ;)) y por otro lado están (estabamos) todos los precarios, entonces le encarga a Rafa que los reparta de una forma sencilla. Rafa como está apuntito de casarse piensa que lo mejor es hacer una aplicación sencilla para que Geno la pueda utilizar y le deje escribir su tesis, que aunque él cree que la lleva bien aún le queda por escribir unas 100 páginas.
La aplicación será llamada Brown Dispatching y su modelo de datos generaría unas 3 tablas:
  • Una tabla para cada miembro del labo, donde podríamos incluir el nombre del precario, el nombre de la máquina, las horas que está o cualquier otra información que pudiese resultar útil para esta situación. En el caso del ejemplo, creo que con el nombre bastaría, además que somos pocos y nos conocemos perfectamente.
  • Otra tabla para cada marrón, indicando el nombre, una descripción y una fecha límite por poner unos campos de ejemplo.
  • La tercera tabla sería la que finalmente enlazaría a los marrones con los precarios. Por lo que tendría unicamente el identificador único de marrón y el identificador único de usuario.
Gracias a Hibernate, esta tercera tabla no habría que implementarla, pero si que deberíamos implementar las otras 2 entidades. A partir de la versión 1.5 existe una opción para meter anotaciones en el propio código del Bean y éste ha sido el método que he elegido yo para realizar el ejemplo.
imports ...
@Entity
@Table(name = "T_PRECARIOS")
public class Precario implements IGwtSerializableParameter {

 private Long id;
 private String name;
 private Set browns;

 // ID SETTER AND GETTER
 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 @Column(name="ID")
 public Long getId() {
  return id;
 }
 public void setId(Long id) {
  this.id = id;
 }

 // NAME SETTER AND GETTER
 @Column(name = "NAME", nullable = false)
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }

 // BROWNS SETTER AND GETTER
 @ManyToMany(
   cascade = { CascadeType.MERGE,
      CascadeType.PERSIST },
   fetch = FetchType.EAGER
   )
 @JoinTable(
   name = "T_PRECARIOS_BROWNS",
   joinColumns = { @JoinColumn(name = "PRECARIO_ID") },
   inverseJoinColumns = { @JoinColumn(name = "BROWN_ID") }
   )
 public Set getBrowns() {
  return browns;
 }
 public void setBrowns(Set browns) {
  this.browns = browns;
 }
 ...
}
import ...
@Entity
@Table(name = "T_BROWNS")
public class Brown implements IGwtSerializableParameter {

 private Long id; // Unique identifier for brown
 private String name; // Brown's name
 private String description; // Brown's description
 private Date finalDate; // Brown's final date
 private Set precarios; // Set with the "precarios" associated

 // SETTER AND GETTER FOR ID
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "ID")
 public Long getId() {
  return id;
 }
 public void setId(Long id) {
  this.id = id;
 }

 // SETTER AND GETTER FOR NAME
 @Column(name = "NAME", nullable = false)
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }

 // SETTER AND GETTER FOR DESCRIPTION
 @Column(name = "DESCRIPTION", nullable = false)
 public String getDescription() {
  return description;
 }
 public void setDescription(String description) {
  this.description = description;
 }

 // SETTER AND GETTER FOR FINAL DATE
 @Column(name = "FINAL_DATE", nullable = false)
 @Temporal(TemporalType.DATE)
 public Date getFinalDate() {
  return finalDate;
 }
 public void setFinalDate(Date finalDate) {
  this.finalDate = finalDate;
 }

 // SETTER AND GETTER FOR "PRECARIOS"
 @ManyToMany(
   mappedBy = "browns",
   cascade = { CascadeType.MERGE,
      CascadeType.PERSIST },
   fetch = FetchType.EAGER
   )
 public Set getPrecarios() {
  return precarios;
 }
 public void setPrecarios(Set precarios) {
  this.precarios = precarios;
 }
 ...
}
En modo de anotaciones de Hibernate, las notaciones se pueden poner en la definición del atributo o en el Getter del mismo, como se puede ver yo he elegido ponerlas en el getter.
Las anotaciones más importantes para el ejemplo que he traído son las asociadas a los Set (de java.util). En estas se representa que tipo de unión se quiere entre las entidades.
En la entidad Precario, se define por un lado el tipo de unión que se va hacer entre las tablas, con los atributos cascade y fetch en la anotación ManyToMany, mientras que en la anotación JoinTable se indica el nombre de la tabla resultante de hacer el join de las entidades y el nombre de las columnas. En la entidad Brown, se define simplemente el ManyToMany indicando que atributo de la otra clase modela está relación, y se indica el tipo de unión que se realiza.
Creo que esto es suficiente clase sobre Hibernate de momento, pero si alguien tiene alguna duda/sugerencia al respecto soy todo oídos. Por cierto, puede que haya alguna manera más eficiente para modelar esto, pero no se me ha ocurrido un ejemplo que modele mejor las necesidades de crear un ManyToMany, y también puede ser que haya forma mejor de realizar el ManyToMany dado que apenas llevo unos meses con Hibernate y no soy ni mucho menos un experto. Aqui solo he tratado de plasmar mi experiencia con esto. Un saludo!

miércoles, 2 de junio de 2010

Abajo esas etiquetas

Yo creo que a todos nosotros, a modo de introducción, nos dijeron que el HTML/XML es un formato de texto plano fácilmente legible y editable por humanos en el que se puede formatear cualquier documento. Nos mintieron. Si editar HTML cumpliese esas promesas no utilizaríamos procesadores de texto ni se editaría la Wikipedia en wikicode, ni las entradas de los foros en BBCode.

Cuando preparamos un fichero README al distribuir software, la tradición manda que esté escrito en texto plano y a no más de 80 columnas para que pueda ser utilizado en el mayor rango posible de situaciones (adicionalmente se pueden incluir versiones en HTML o PDF). Hoy me gustaría recomendaros el formato markdown para este tipo de tareas porque tiene una sintaxis simple, existen herramientas para traducir los documentos a otros formatos y por encima de todo, es un formato directamente legible.

Existen muchos ejemplos en github, una web que se merece un apunte propio, puesto que soporta markdown y permite visualizar en texto plano o el resultado de procesarlo.

Como ventaja adicional, el hecho de adoptar markdown nos facilitará el ser consistentes con la notación de los documentos.

Algunas herramientas que podemos usar son el propio paquete markdown (debian | script en perl), pandoc (diversas conversiones), htmldoc (para pasar a pdf un html) y muchas otras utilidades. A la hora de editar markdown desde vim, podemos utilizar un poco de magia de vim.org: http://www.vim.org/scripts/script.php?script_id=2882

viernes, 21 de mayo de 2010

Git en tu prompt

Ultimamente, GIT está causando furor entre los miembros del labo. Aunque el cambio desde Subversion puede ser algo traumático si no se digieren bien los nuevos conceptos, el cambio de paradigma hacia el control de versiones distribuidos merece mucho la pena. Una buena introducción es el libro online Pro Git (recomendación vía Álvaro).

Hoy quiero compartir un snippet que permite personalizar el PROMTP de bash para que muestre en que rama de un repositorio GIT estamos trabajando y un asterisco si tenemos cambios pendientes. Para usarlo, basta con que lo copiéis a vuestro home y lo llaméis desde el .bashrc.

Como característica extra, el prompt cambia de color si abrís una shell de root para que no se os olvide cerrarla.


Actualización: si utilizáis el git desde los ports de mac, echadle un vistazo a este hilo para habilitar el comando __git_ps1

martes, 11 de mayo de 2010

Remontadas

Los sistemas de ficheros compartidos por red son muy útiles a mi me simplifican mucho la tarea de almacenar copias de seguridad en una máquina diferente. Basta con tener montada la partición y usarla como si fuese local.

Sin embargo, cuando hay problemas de red o cortes de luz puede ser necesario montar o remontar esas particiones y se puede tardar bastante tiempo en detectar si no se tiene cuidado. Una forma de atacar el problema es tener a mano un script en el cron. A continuación pego el que acabamos de poner en funcionamiento en el labo:

Podéis probarlo con la opción --verbose para ver qué hace paso a paso y que puede resumirse en comprobar si el montaje esta ido o desmontado y actuar en consecuencia. No olvidéis sustituir los puntos de montaje al principio del script!

lunes, 26 de abril de 2010

Limpiar ficheros en Python

¿No os molestan los ficheros, en general de código fuente, que están llenos de espacios al final de las líneas (los llamados trailing spaces) y otras degeneraciones varias: tabuladores mezclados con espacios normales, fines de línea estilo MS-DOS (retornos de carro) mezclados con otros UNIX, etc.? A nosotros sí.

Este es un problema que surge cuando un equipo trabajan sobre los mismos ficheros de texto, cada uno con su editor, en su sistema operativo... y entre Álvaro, Sebas y yo nos hemos propuesto solucionarlo.

Para ello, hemos creado un script en Python que toma como argumentos una lista indeterminada de ficheros y los "limpia". En concreto:

  • Elimina espacios y tabuladores al final de todas las líneas.
  • Elimina los retornos de carro estilo MS-DOS, para homogeneizarlos y que se vean "bonitos" en todos los entornos.
  • Opcionalmente, por medio del paso de un parámetro extra, se sustituyen los tabuladores de principio de línea por 4 espacios.
El uso es bien sencillo: 
python sanitize_nl.py [--retab] <fichero1> [<fichero2> ...]
...y listo. Ficheros limpitos y sin problemas.

Podeis descargarlo de aqui

jueves, 8 de abril de 2010

JSON con comentarios

JSON es un formato que permite representar estructuras de datos de una manera muy sencilla y compacta para su uso en aplicaciones web. El formato es deliberadamente simple y austero para evitar problemas, por ejemplo, sólo se utilizan comillas dobles y no se permiten comentarios.

Pero, ¿qué sucede si queremos utilizar JSON para representar configuraciones? Los comentarios son importantísimos y los parsers existentes no lo contemplan. Podríamos meternos en un infierno de expresiones regulares con los problemas que eso puede traer (las regex se quedan cortas para este tipo de trabajos) pero es mejor disponer de un parser adaptado a esta tarea.

Partiendo de la última versión del parser escrito en JavaScript de JSON.org hemos añadido los comentarios de línea (//) y bloque (/* */). Esta opción es más lenta que los parsers integrados en el navegador pero, a fin de cuentas, los ficheros de configuración no deberían ser enormes con lo que es un buen compromiso.

El resultado lo podéis descargar aquí: commented json parser. Para usarlo basta con incluir la biblioteca e invocarlo así:

var object = cjson_parse('{ "hola": /* adios */ "3", \n\
 "cumpleaños": "2009-12-12" // fecha temporal\n\
}');

miércoles, 7 de abril de 2010

El arte de programar

Leído en Watch What I Do: Programming by Demonstration


This urge to create something living is common among artists. Michelangelo is said to have struck with his mallet the knee of perhaps the most beautiful statue ever made, the Pieta, when it would not speak to him. And then there's the story of Frankenstein. Artists have consistently reported an exhilaration during the act of creation, followed by depression when the work is completed. "For it is then that the painter realizes that it is only a picture he is painting. Until then he had almost dared to hope that the picture might spring to life." (Lucien Freud, in [Gombrich 60], p.94) This is also the lure of programming, except that unlike other forms of art, computer programs do "come to life" in a sense.

viernes, 12 de marzo de 2010

Code Bubbles

A través de Alarming Development he dado con el proyecto Code Bubbles, un soplo de aire fresco para el mundillo de los IDEs del que habla por sí solo el siguiente vídeo.

Su objetivo es proporcionar una forma ágil de trabajar con proyectos (Java en su demo) en los que el número de ficheros y funciones que dependen de otras en múltiples niveles hacen que se consuma mucho tiempo cambiando entre ficheros (¿habéis trabajado en un proyecto con ~100 clases?).

Si estuviese en producción yo querría probarlo. De momento, es posible solicitar participar en sus pruebas de beta.

En cualquier caso, me parece fantástico que se continúe investigando formas de mejorar los entornos de desarrollo como ésta, que derrocha creatividad. Sólo le veo una barrera importante de adopción que no sea fácil de solucionar puliendo los detalles y es que la curva de aprendizaje tiene que ser pronunciada.

Code Kata: cadenas de Márkov

El code kata de esta semana trata sobre las cadenas de markov, una herramienta matemática que acecha oculta en cursos de estadística o investigación operativa y que si visitáis la Wikipedia veréis que se utiliza para infinidad de cosas como la redacción de spam.

¿Qué es una cadena Márkov? No es más que un proceso estocástico en el que el último suceso nos aporta todo lo que podemos saber acerca de los siguientes sucesos o, en castellano llano, un generador aleatorio en el que el último resultado determina las probabilidades para el siguiente. Si además es homogéneo, de primer orden y el resto de cosas para no complicarnos demasiado podemos representar la cadena de Márkov como una matriz de n x n en el que P(i,j) nos marca la probabilidad de que j le siga a i.

Los que sigan leyendo esta entrada se preguntarán para qué puede ser útil todo esto y por qué no están escribiendo las memorias de sus prácticas, TFCs, documentación de su proyecto o alguna otra cosa útil o inevitable. Quizá no estéis perdiendo el tiempo, las cadenas de Márkov pueden utilizarse para generar textos de relleno tan incoherentes como los que deberíais estar escribiendo sin el riesgo de que alguien se de cuenta de que habéis copyshiteado media wikipedia. Para ello basta con tomar las palabras y signos de puntuación como los símbolos de salida de la cadena y entrenarla con un corpus de texto inicial (otros documentos o prácticas anteriores). Los resultados son fascinantes y pondré dos ejemplos.

Garkov es una tira cómica que se autogenera con cada visita. Se basa en un catálogo de tiras de Garfield de las que han borrado los textos y una cadena de Márkov que genera el texto. El resultado varía entre surrealista y plausible, podéis probar todo lo que os apetezca.


Garfield + cadenas de Markov = Garkov

El segundo ejemplo ha sido generado con una cadena de primer orden entrenada a partir de algunos documentos antiguos en los que he participado, es difícil juzgar si la causa del sentimiento de irrealidad es debido a la cadena o al corpus para entrenarla.

In this task is responsible for the planned work packages, Definition R it will also Coordinator will be used technical risk are described in the creation of technology for carrying out, to existing know how will is a common state of the two different concern within level of architecture of Lifecycle other cases.

A veces, el resultado puede dar miedo y/o ser poético:

Mashup platforms, family that involve human Embryos?

Code kata: cadenas de Márkov

Andrey Markov
El bueno de Andrey Markov

Volviendo al code kata, nuestro objetivo consistirá en implementar un generador aleatorio mediante una cadena de Márkov de primer orden (y no volver a tener que escribir relleno a mano).

El primer problema a resolver consistirá en la capacidad de convertir el corpus, en principio uno o varios ficheros de texto plano, en una secuencia de tokens que podrán ser o bien palabras o bien signos de puntuación. El punto y el final de fichero tendrán una función especial, marcarán el fin de la sentencia.

Este primer paso puede ser más o menos elaborado dependiendo del tiempo e interés que se quiera dedicar. En el mejor de los casos se deberían intentar preservar más información del fichero de entrada, como por ejemplo considerar una o varias líneas en blanco como otro fin de sentencia.

El siguiente elemento a resolver será la representación de la cadena, que en teoría sería una matriz cuadrada con todas las palabras de corpus como filas y columnas. Quizás se deba recurrir a alguna técnica para almacenar matrices dispersas...

Opcionalmente se puede considerar la carga y el almacenamiento de cadenas desde ficheros en disco para ahorrarse el proceso de entrenamiento de la cadena.

Finalmente se debe implementar la generación de texto.

Buena suerte y no dudéis en mirar la Wikipedia o rastrear Internet para reunir más información, es parte del ejercicio.

jueves, 11 de marzo de 2010

Actualizado Acerca de...

Hemos actualizado la nota acerca de.... Lectura obligada ;)

miércoles, 10 de marzo de 2010

Neologismo: Copy & Shit

Hoy quiero lanzar un neologismo al mundo: copy & shit. Se puede dudar si esta expresión tiene alguna ventaja sobre el típico y tradicional "copy & paste" aparte de desconcertar a la gente a vuestro alrededor. Mi argumento es claro, esta expresión es preferible cuando se está desarrollando código ya que nos pone automáticamente en guardia sobre los problemas que podemos introducir al copiar unas pocas líneas de una clase a otra. Es posible que esto nos lleve a pensar en extraer el código a una función o clase independiente o reflexionar sobre el diseño para evitar la duplicación de código.

El siguiente poster motivacional puede servir para hacer propaganda sobre este novedoso concepto. También podéis ser fans en Facebook!

Copy & Shit: because one bad programmer can create 2 new jobs a year

Asamblea de la Comunidad Morfeo

Logo aniversario Morfeo
Sí, es hotlinking, pero somos pobres :(

Se está celebrando ahora mismo (wow, live blogging) la tercera asamblea de la Comunidad Morfeo en cuyos proyectos tantos labos y exlabos hemos pasado. Los comentarios en tiempo real se pueden seguir mediante el tag #morfeo2010 en twitter y el mismo tag en flickr.

La jornada está resultado mucho más interesante y abierta a contribuciones externas que otros años, con presentaciones de mucha calidad. Me gustaría destacar un par de presentaciones que todavía estamos digiriendo: TIBI por Sergio Montero y ASOLIF por @Dakal (siento no haber anotado el nombre).

TIBI es una asociación de emprendedores de software e Internet que, como nos cuenta Sergio Montero, es una organización jóven, dinámica y que huye de la institucionalización y permite que sus socios emprendedores curen su soledad y compartan conocimiento. Por ejemplo, su última reunión trató sobre cómo posicionar productos software en España. Nos ha transmitido la visión y la ilusión de las pequeñas empresas tecnológicas y su esfuerzo por salir de salir de la España del 600 y la alpargata.

La presentación de ASOLIF, la asociación de empresas españolas del software libre, ha continuado de cierta forma con el tema de la nueva generación de empresas tecnológicas que está creciendo aún a pesar de la crisis (3%). Y todo esto llevando con honor la etiqueta frikipower como alternativa (y complemento) a las grandes empresas establecidas que quizás tengan más conocimiento sobre negocio que sobre tecnología.

Como muestra de pluralidad de pensamiento, ASOLIF se muestra reacia a creer en las certificaciones (línea de trabajo de Morfación) y apuestan por las guías y libros blancos.

Esto es todo por el momento, seguimos en la brecha

martes, 9 de marzo de 2010

Clone HashMap de HashMap

Si bien el otro día Sebas nos hablo del uso de las dobles llaves para sobrescribir el constructor de una clase anónima en java, no hemos tardado más de 2 días en necesitar usarlo.

El problema ha venido al intentar clonar un objeto del tipo HashMap con otro Map dentro. Esto se debe a que se intenta clonar un objeto que dentro tiene otro objeto, y para clonarlo se debe hacer la clonación por separado de dicho objeto.

Un modo de solucionarlo es declarar el tipo del Map que hay dentro del Map que se quiere clonar como final.Pero esto no siempre es posible.

El otro método que se nos ha ocurrido para solucionarlo ha sido emplear la inicialización de la doble llave, y el resultado ha sido algo de este estilo.

 HashMap cloned = new HashMap();

  for (Object key: reference.keySet()) {
    final Map map = reference.get(key);
    cloned.put(key, new HashMap() {{
      for (Entry entry: map.entrySet()) {
        put(entry.getKey(), entry.getValue());
      }
    }});
  }

Y esto es todo por hoy. Espero vuestras opiniones o soluciones alternativas.

domingo, 7 de marzo de 2010

Envidias...


Fotografía de JC Olivera

Los compañeros del laboratorio utilizamos o hemos utilizado muchos lenguajes de programación teniendo cada uno nuestras preferencias personales más o menos pasajeras. Esto da bastate pie a la comparación y a comprobar y desmentir tópicos.

Una comparación típica es Java vs lenguajes de scripting (Python, JavaScript, Perl) y qué cosas se echan de menos o se envidian cuando se programa en Java. Pongamos como ejemplo la cantidad de líneas que hacen falta para solucionar cualquier problema en Java comparadas con un poco de hacking en Python o Perl. Como explican en el Schneide Blog:

Quiz: Whats one of the most heard flaws of Java compared to other languages?
Bad Performance? That’s a long overhauled myth. Slow startup? OK, this can be improved… It’s verbosity, right? Right but wrong. Yes, it is one of the most mentioned flaws but is it really inherit to the language Java?

La entrada, que es muy interesante, termina concluyendo que la culpa no es del lenguaje Java sino del diseño de las bibliotecas. Quizás Python y Perl le deben tanto a sus bibliotecas oficiales y al CPAN como a su sintaxis.

Una característica my envidiable es la facilidad pasmosa con la que se crean hashes de hashes en los lenguajes de scripting y para muestra un JSON:

var a = {
    "rojo": { "fichas": [1, 3, 4], "nombre": "juan" },
    "amarillo": { "fichas": [22], "nombre": "pedro" }, 
}

Lo más parecido que tenemos en Java son las clases derivadas anónimas, también conocidas como Double Brace Initialization (suena a jugada de los hermanos Derrick).Para utilizarlo, tras invocar al constructor se añade código de inicialización entre dos pares de llaves. El efecto es una clase anónima derivada de la clase cuyo constructor se invoca y que lleva adosado al constructor las líneas extra que se quiera. Repitiendo el ejemplo anterior:

Map a = new HashMap() {{
    put("rojo", new HashMap() {{
        put("fichas", new int[] {1, 3, 4});
        put("nombre", "juan");
    }});
    put("amarillo", new HashMap() {{
        put("fichas", new int[] {22});
        put("nombre", "pedro");
    }});
}};

La verdad es que sigue siendo bastante más verboso que en JavaScript, pero es un avance... Además, podemos utilizar los generics para tener tipado estático mucho más concreto que en un JSON. ¿Tenéis alguna forma más cómoda de hacerlo? ¿Y otros trucos parecidos? Los comentarios son bienvenidos.

viernes, 5 de marzo de 2010

Joose: JavaScript OOP ¡Por fin!

Me estreno en este blog (muy tarde, lo siento) con una entrada acerca de un framework JavaScript que acabo de descubrir, que me parece va a estar presente en mis futuros desarrollos: Joose. Esta librería se centra en uno de los aspectos más pobres de JavaScript, la Orientación a Objetos.

¿Para qué otro framework más?


Existen en la red multitud de frameworks para facilitar la tarea del desarrollador Web (tarea, por otro lado, bastante ingrata sin el uso de alguno o varios de estos frameworks). En general, la mayoría de ellos se centran en facilitar el acceso al DOM, las llamadas AJAX, e incluso ofrecer un entorno para desarrollo de interfaces de usuario.  Sin embargo, Joose se distingue de sus alternativas por enfocarse en el área quizá mas pobre de JavaScript, la orientación a objetos. A pesar de que otros frameworks como Prototype o Dojo ofrecen sus propios métodos para conseguir "más o menos" orientación a objetos en JavaScript, ninguno se acerca a la funcionalidad y organización de Joose. Según los propios desarrolladores, Joose ofrece "orientación a objetos postmoderna" en JavaScript.

Características básicas


No os voy a aburrir con detalles de implementación o documentación exhaustiva (la página os puede proporcionar mucha información), pero os cuento cosas que me han sorprendido gratamente:

  • Mecanismos habituales en la OO, como herencia (múltiple), interfaces, clases abstractas, singletons, etc, pero bien hecho.
  • Getters y Setters automáticos
  • Paquetes (espacios de nombres)
  • Roles (interfaces con esteroides)
  • Filosofía cercana a la orientación a aspectos
  • Persistencia automática de objetos con el storage de HTML5 y (creo) con recursos remotos usando AJAX
  • Reflexión de código y otras cosas chungas que sólo Sebas comprende

Show me the code!


Como este viernes no hay kata, como ejemplo de código publico una solución parcial (lo demás lo implementáis vosotros para probar el framework) a la kata cuatro cuatros de hace un par de semanas.

Role (interfaz) Printable, que requiere implementar el toString:

Role("Printable", {
 requires: "toString"
});

Clase Abstracta Exp, con un método estático (de clase). Implementa Printable:

Class("Exp", {
 does: Printable,
 methods: {
  toString: function(){},
  count4: function(){},
  getValue: function(){}
 },
 classMethods: {
  findExpresion(number) {
   // Resuelvelo tu
  }
 } 
});

Clase Op, que hereda de Exp:

Class("Op", {
 isa: Exp,
 has: {
  _operand: {is: "rw"},
  _left: {is: "rw"},
  _right: {is: "rw"}
 },
 override: {
  toString: function() {
   return "(" + this._left.toString() + this._operand + this._right.toString() + ")"
  },
  count4: function() {
   return this._left.count4() + this._right.count4()
  },
  getValue: function() {
   var result;
   switch(this._operand) {
    case "+":
     result = this._left.getValue() + this._right.getValue();
     break;
    case "-":
     result = this._left.getValue() - this._right.getValue();
     break;
    case "*":
     result = this._left.getValue() * this._right.getValue();
     break;
    case "/":
     if (this._left.getValue() % this._right.getValue() == 0) {
      result = this._left.getValue() / this._right.getValue();
     } else {
      throw "ValueError";
     }    
     break;
   }
   return result;
  }
 }
});

Clase Num, que también hereda de Exp:

Class("Num", {
 isa: Exp,
 has: {
  _value: {is: "rw"}
 }, 
 override: {
  toString: function() {
   return this._value
  },
  count4: function() {
   var stringifiedNumber = this._value + "";
   return countOcurrences(stringifiedNumber, '4');
  },
  getValue: function() {
   return this._value;  
  }
 }
});

Por último,una pequeña prueba de unidad (se usa el console.log que ofrece Firebug). Además, una función auxiliar que siendo puristas habría que haber metido en una clase.

countOcurrences = function(text, character) {
   return (text.length - text.replace(new RegExp(character,"g"), '').length / text.length);
  }

var exp = new Op({ 
  operand: '-', 
  left: new Num({value: 44}), 
  right: new Op({
   operand: '*', 
   left: new Num({value:4}), 
   right: new Num({value:4})})});
console.log(exp.toString());
console.log(exp.count4());
console.log(exp.getValue());

Esto es todo por hoy, espero que os haya gustado, y procuraré postear más a menudo.

jueves, 4 de marzo de 2010

Diseño UML Code Kata Parchis

Hola a todos (o a los pocos que dedicáis vuestro tiempo de procrastinación con este blog)
Tras casi una semana con el code kata del parchis voy a poner por fin el diseño en UML que hemos creído que mejor representa el escenario propuesto.
En la siguiente imagen podéis ver el diseño en un cuaderno que hemos dado a este problema, al final ha quedado un diseño bastante simple y en mi opinión bastante claro. Ante cualquier duda, ya sabéis un comentario y estaremos encantados de responderos.
Diseño kata parchis
Ya me despido y espero que el diseño os haya gustado a todos. Esta semana la dejaremos seguramente para que quien quiera implemente el parchis y la semana que viene dejaremos aquí nuestro resultado.
Un saludo a todos.

viernes, 26 de febrero de 2010

Code Kata: parchís

Con el code kata de esta semana intentaremos mejorar nuestras dotes de modelado orientado a objetos y diseño.


Imagen de Santi Oliveri

Nuestro objetivo será modelar utilizando el paradigma orientado a objetos (o alguna aproximación si se utilizan otros paradigmas) para modelar el juego del parchís. Este juego de orígenes lejanos y orientales ha dado lugar muchísimas variantes (parchisi, ludo, por parejas) y la idiosincracia española ha contribuido a crear variantes por nuestra tendencia a inventarnos normas ad-hoc favorables a nuestra causa. Para evitar discusiones a continuación se incluye el parchís normalizado para exlabos (release candidade 1). Proximamente se enviará al W3C para su estandarización.

Parchis para exlabos RC1

Definiciones previas:

Jugador
Cada uno de los participantes. En una partida existen de 2 a cuatro y cada uno de ellos utiliza un color direfente
Color
Hay cuatro colores, por orden: amarillo, azul, rojo y verde
Ficha
Cada jugador tiene 4 fichas de su color ocupando alguna casilla.
Casilla
Cada uno de los lugares en los que pueden estar las fichas en el tablero. Hay 68 casillas comunes y 8 en la escalera de cada jugador (recta final coloreada). Las casillas tienen una capacidad máxima de, en general 2 fichas. Aunque parezca obvio, de la 68 se pasa a la 1.
Casa
Posición inicial de las fichas que no están en juego para cada jugador, lo que viene siendo el limbo. Capacidad: 4 fichas.
Escalera
Las últimas ocho casillas del camino exclusivas para cada jugador.
Seguro
Casillas especiales en las que no se capturan fichas. Hay 12: 5, 12, 17, 22, 29, 39, 46, 51, 58, 63, 68.
Salida
Seguro con el color de un jugador y punto de entrada de sus fichas desde su casa al ponerse en juego con un 5.
Meta
Última casilla de cada escalera. Capacidad: 4 fichas.
Puente
Dos fichas del mismo color en la misma casilla. Impiden el paso a cualquier ficha. (Tomad esto literalmente.)
Captura
Cuando se mueve una ficha a una casilla ya ocupada por una ficha de otro jugador esta es capturada. La ficha vuelve a su casa y el jugador cuenta 20 (si procede)
Turno
Lo que viene siendo un turno, avanzando en sentido anti-horario
Movimiento
Trasladar cualquier ficha que no esté ni en casa ni en la meta hasta el número de casillas por delante que se esté contando si la casilla de destino no está llena y no hay que atravesar puentes.
También se considera mover una ficha desde casa a la salida cuando se tiene una tirada de 5.

Inicio del juego. Al comenzar, cada jugador tendrá cuatro fichas en su casa. El que saque una tirada preliminar mayor disfrutará del primer turno. En caso de empate se vuelve a tirar.

Turno de un jugador.

Se tira el dado, si se saca...
  • 5. Si quedan fichas en casa y la salida no está llena, se pone en juego una ficha. Si no, se mueve contándose 5 y en siguiente turno será para el siguiente jugador (amarillo -> azul -> rojo -> azul -> amarillo -> ... imaginad el ciclo del rey león).
  • 6.
    • Primer y segundo turnos consecutivos. Contarse 6 (7 si no quedan fichas en casa) y el siguiente turno será del mismo jugador.
    • Tercer turno consecutivo. La última ficha movida vuelve a la casa a no ser que se encuentre en la escalera y termina el turno.
  • Resto de tiradas. Se cuentan las casillas correspondientes a la tirada.

Mover una ficha. Si se está contando 6 o 7 y alguno de los movimientos posibles (ver definición) puede romper un puente se debe romper un puente (nobleza obliga). En otro caso se elige cualquier movimiento posible o no se mueve si no existe ninguno.

Si existe captura, se vuelve a mover una ficha, contándose 20 esta vez.

Si se alcanza la meta, se vuelve a mover una ficha, contándose 10.

Fin del juego. Si todas las fichas de un jugador llegan a su meta ha ganado y finaliza la partida. En teoría se podría continuar hasta que ganasen n-1 jugadores, pero no tiene ningún interes.

Parchis Kata

El objetivo es modelar el juego descrito en las normas anteriores pero no de cualquier forma. Es necesario:
  • Poder representar mediante un objeto cada estado del juego. No es necesario representar la tirada inicial que decide que jugador comienza.
  • La interfaz debe ser lo más natural y sucinta posible. Debe ser posible recuperar la información necesaria para representar el estado del juego y también para ejecutar los movimientos de los jugadores.
  • En concreto, se debe prestar especial atención a las diferentes acciones que un jugador pueda elegir. Se tienen que poder listar como objetos antes de decidirse por uno de ellos.
El kata se puede ejercitar hasta diferentes niveles de detalle:
  • Representación inicial mediante UML o cajitas en una servilleta
  • Interfaces concretas para los diferentes objetos
  • Implementación de los métodos (y sus pruebas de unidad para comprobar que se cumplen las normas)
Esto es todo por el momento, disfrutad!

martes, 23 de febrero de 2010

Cuatro cuatros code kata: show me the code!

El viernes pasado hubo un éxito en cuanto a seguimiento del code kata con gente implementando el problema en Java, Python, JavaScript y Haskell. Sin embargo, la mayoría se quedó en el punto 5, con la búsqueda de expresiones para un determinado valor.

Muchos os estaréis preguntando cómo se puede resolver ese punto (show me the money, esto, the code!). Los impacientes pueden descargar mi solución en Java.

Los primeros puntos se resuelven creando una pequeña jerarquía de clases o una interfaz y dos clases que la implementen:

  • Clase abstracta/interfaz Exp. Declara los métodos getValue(), count4() y, puede servir más adelante para incluir el método estático findExp.
    public abstract class Exp {
    
        public abstract int getValue() throws ValueError;
    
        public abstract int count4();
    
        protected abstract String toString(int priority);
    
    
        public static Exp findExp(int target) {
            ...
        }
    }
    
  • Clase Num. Muy simple, basta con contar los dígitos y almacenar un entero.
    public class Num extends Exp {
    
        public Num(int num) {
            assert all4(num);
            this.num = num;
        }
    
        @Override
        public int getValue() {
            return this.num;
        }
    
        @Override
        public String toString() {
            return Integer.toString(this.num);
        }
    
        @Override
        public int count4() {
            return Integer.toString(num).length();
        }
    
        public static boolean all4(int num) {
            while (num > 10) {
                int lastDigit = num % 10;
                if (lastDigit != 4) {
                    return false;
                }
    
                num = num / 10;
            }
    
            return num == 4;
        }
    
        private final int num;
    
        @Override
        protected String toString(int priority) {
            return this.toString();
        }
    }
    
  • Clase Op. Se basa en tres atributos, un caracter para determinar el operador concreto y dos enlaces a las sub-expresiones (left y right). Para los operadores unarios se utiliza sólo uno de los enlaces.
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     *
     * @author sortega
     */
    public class Op extends Exp {
    
        public Op(char operator, Exp left, Exp right) {
            assert left != null;
            assert right != null;
            assert "+-*/".contains("" + operator);
            this.left = left;
            this.right = right;
            this.op = operator;
        }
    
        public Op(char operator, Exp child) {
            assert child != null;
            assert "!V".contains("" + operator);
            this.left = child;
            this.right = null;
            this.op = operator;
        }
    
        @Override
        public int getValue() {
            int leftValue = this.left.getValue();
    
            if (this.isBinary()) {
                int rightValue = this.right.getValue();
    
                switch (this.op) {
                    case '+':
                        return leftValue + rightValue;
    
                    case '-':
                        return leftValue - rightValue;
    
                    case '*':
                        return leftValue * rightValue;
    
                    case '/':
                        if (leftValue % rightValue != 0) {
                            throw new ValueError();
                        }
                        return leftValue / rightValue;
    
                    default:
                        throw new IllegalStateException();
                }
                
            } else {
                switch (this.op) {
                    case '!':
                        return fact(leftValue);
    
                    case 'V':
                        int square = (int) Math.sqrt(leftValue);
                        if (square * square == leftValue) {
                            return square;
                        } else {
                            throw new ValueError();
                        }
    
                    default:
                        throw new IllegalStateException();
                }
            }
        }
    
        @Override
        public String toString() {
            if (this.isBinary()) {
                return this.left.toString(this.getOpPriority()) + this.op +
                    this.right.toString(this.getOpPriority());
            } else {
                String operand = this.left.toString(this.getOpPriority());
                switch (this.op) {
                    case '!':
                        return operand + '!';
    
                    case 'V':
                        return 'V' + operand;
    
                    default:
                        throw new IllegalStateException();
                }
            }
        }
    
        @Override
        public int count4() {
            return this.left.count4() +
                    (this.isBinary() ? this.right.count4() : 0);
        }
    
        private static final Map OPERATOR_PRIORITIES =
                new HashMap() {{
                    put('!', 1); put('V', 1);
                    put('*', 2); put('/', 2);
                    put('+', 3); put('-', 3);
                }};
        
        private final char op;
        private final Exp left;
        private final Exp right;
    
    
        private int fact(int n) {
            int fact = 1;
            for (int i = 0; i < n; i++) {
                fact *= n;
            }
            return fact;
        }
    
        private boolean isBinary() {
            return this.right != null;
        }
    
        private int getOpPriority() {
            return OPERATOR_PRIORITIES.get(this.op);
        }
    
        @Override
        protected String toString(int priority) {
            if (this.getOpPriority() > priority) {
                return "(" + this.toString() + ")";
            } else {
                return this.toString();
            }
        }
    }
    
En cuanto al método findExp, lo primero que debe venirnos a la mente es el backtracking como forma de construir el árbol con la expresión deseada. Sin embargo, cuanto más inteligente sea la forma de generar los nodos que se prueban, más eficiente será el proceso. En la solución propuesta se realiza de la siguiente forma (pseudocódigo):
  • Buscar expresión para el número N -> Buscar expresión para el número N con 4 cuatros.
  • Buscar expresión para un número N con R cuatros
    • Es N igual a R cuatros? -> Devolver new Num(N)
    • Por cada número concebible usando de 1 a R cuatros
      • Por cada operador binario. Es posible encontrar una expresión (llamada recursiva con N y R - los cuatros usados) resultante de aplicar el operador inverso? En cristiano, si es posible encontrar N - operando entonces devolver new Op('+', operando, sub-expresión encontrada)
      • Hacer algo parecido con los operadores unarios
Si tienes una solución mejor o una explicación inteligible de este método, mándala y actualizamos el post. Mientras tanto, podemos usar el código para aclarar esta explicación:
public static Exp findExp(int target) {
        return findExp(4, target);
    }


    private static Exp findExp(int rem4, int target) {
        Exp result;

        result = findNum(rem4, target);
        if (result != null) {
            return result;
        }

        int operand = 0;
        for (int i = 1; i <= rem4; i++) {
            operand = 10 * operand + 4;

            // Unary operators
            if (rem4 == i) {
                result = new Op('!', new Num(operand));
                if (result.getValue() == target) {
                    return result;
                }

                result = new Op('V', new Num(operand));
                try {
                    if (result.getValue() == target) {
                        return result;
                    }
                } catch (ValueError ex) {
                }
            }

            // Binary operators

            int rightTarget, leftTarget;
            Exp rightExp, leftExp;

            rightTarget = target - operand;
            rightExp = findExp(rem4 - i, rightTarget);
            if (rightExp != null) {
                return new Op('+', new Num(operand), rightExp);
            }

            rightTarget = operand - target;
            rightExp = findExp(rem4 - i, rightTarget);
            if (rightExp != null) {
                return new Op('-', new Num(operand), rightExp);
            }
            leftTarget = target + operand;
            leftExp = findExp(rem4 - i, leftTarget);
            if (rightExp != null) {
                return new Op('-', leftExp, new Num(operand));
            }

            if (target % operand == 0) {
                rightTarget = target / operand;
                rightExp = findExp(rem4 - i, rightTarget);
                if (rightExp != null) {
                    return new Op('*', new Num(operand), rightExp);
                }
            }

            if (target != 0 && operand % target == 0) {
                rightTarget = operand / target;
                rightExp = findExp(rem4 - i, rightTarget);
                if (rightExp != null) {
                    return new Op('/', new Num(operand), rightExp);
                }
            }
            leftTarget = target * operand;
            leftExp = findExp(rem4 - i, leftTarget);
            if (rightExp != null) {
                return new Op('/', leftExp, new Num(operand));
            }

        }

        return null;
    }

    private static Num findNum(int rem4, int target) {
        if (Num.all4(target)) {
            Num num = new Num(target);
            if (num.count4() == rem4) {
                return num;
            }
        }
        return null;
    }
Seguid esforzándoos!

viernes, 19 de febrero de 2010

Cuatro cuatros code kata

De vez en cuando propondremos un code kata, esperamos que los viernes. Se trata de utilizar el lenguaje de programación preferido y practicar.

El de hoy ha sido inspirado por un post de kriptópolis sobre el juego del cuatro:

¿Es posible expresar todos los dígitos del 1 al 20 utilizando cuatro cuatros y operadores matemáticos sencillos (suma, resta, producto, cociente, paréntesis y raíz cuadrada)? Sí... a excepción del 19, que requiere además el punto decimal y/o el signo factorial (!). De hecho, añadiendo estos dos operadores y otro que indique infinitas cifras periódicas (p. ej: ´.4 = 0.4444...) es posible llegar al 112.

La idea, retocada para nuestro propósito consiste en utilizar sólo aritmética entera (no vamos a contemplar números reales ni racionales) y buscar expresiones que contengan exactamente cuatro dígitos 4 y un número arbitrario de operadores +, -, *, / y paréntesis.

De esta forma, una expresión válida para el conseguir el número 8 es "4+4+4-4", y "44-4*4" o "44-(4*4)" para conseguir 28.

Cuatro cuatros kata

  1. Construir expresiones. Se tiene que poder crear expresiones de forma sencilla, ejemplo en Java para "(44-(4*4))".
    Exp exp = new Op('-', new Num(44), new Op('*', new Num(4), new Num(4)));
    
  2. Imprimir expresiones. Se tiene que poder imprimir las expresiones de forma inteligible.
    assertEquals("(44-(4*4)", exp.toString());
    
  3. Comprobar el número de cuatros.
    assertEquals(4, exp.count4());
    
  4. Calcular el valor de la expresión con un método getValue. La división debe ser entera 5 / 4 dará una excepción (por ejemplo ValueError)
  5. Buscar una expresión para un número dado, por ejemplo el 28.
    Exp exp = Exp.findExpression(28);
    assertEquals(4, exp.count4());
    assertEquals(28, exp.getValue());
    
  6. Hacerse un método que busque expresiones para los números del -256 al 256 y cuente las expresiones encontradas (y las encontradas pero que no cumplan las condiciones ;). ¿Cuántas soluciones encuentras?
  7. Repetir añadiendo el operador raíz cuadrada (también entera, vale para 4, pero no para -4 ni para 8) y factorial. Los símbolos serán ! y V.
    Exp exp = new Op('!', new Op('V', new Num(4)));
    assertEquals("!(V(4))", exp.toString());
    assertEquals(2, exp.getValue());
    
    ¿Cuántas expresiones más encuentras? ¿Cuánto tiempo tarda?
  8. Para nota, encontrar las expresiones con el menor número de operadores...

Esto es todo, espero que os guste y ver soluciones ingeniosas

martes, 16 de febrero de 2010

Porra: Cuándo nos intervienen los alemanes?

Tras la noticia sobre la intervención de Grecia, todos nos preguntamos cual es el siguiente cerdo al que le va a llegar el San Martín (PIGS: Portugal, Italy, Greece, and last but not least, Spain).

Convocamos a los labos y exlabos y otros especímenes a opinar en esta porra-encuesta sin ánimo de lucro.

Grecia ya ha caído, seguramente seamos los siguientes. ¿Conseguirá Zapatero presidir la institución que intervenga su propio país? Todo es posible.

No se vosotros, pero de momento nadie propone que terminemos el año con honor.

Un saludo

lunes, 15 de febrero de 2010

URL Extender

Yo no se a vosotros, pero a mí las URLs me gustan largas. El caso es que necesitábamos extender una URL añadiendo elementos al path de la misma en Python y resulta ser muy fácil gracias al módulo urlparse:
def url_extend(url, extra_path_parts):
     (scheme, netloc, path, params, query, fragment) = urlparse(url)
     path = '/'.join(path.split('/') + extra_path_parts) + ('/')
     return urlunparse([scheme, netloc, path, params, query, fragment])
Un ejemplo de uso:
print url_extend('http://exlabos.blogspot.com/exto/si?hola=true', ['extra', 'path'])
>> 'http://exlabos.blogspot.com/exto/si/extra/path/?hola=true'
BTW, un saludo a todos los labos y exlabos.

martes, 9 de febrero de 2010

It Works!

Hola a todos, Este es un mensaje para advertiros a todos de que hay un proyecto en marcha mediante el cual se pretende contar las vivencias y andaduras de los miembros (y ya no tan miembros) del labo. En este blog se pretende explicar cualquier cosa que nos suceda y qué consideremos al menos interesante y qué creamos que debería saber todo el mundo. De este modo trataremos de evitar situaciones como: "Te acuerdas de... eh! que a mi no me habéis contado eso!" o las típicas situaciones de "No he encontrado una solución para mi problema" o como cuando encuentras a alguien que tiene el mismo problema pero lo soluciona sin contarlo.
No perderé la oportunidad de decir que esto será algo parecido a un "ceiling-cat" y para quien quiera uno en casa tan solo tiene que coger está plantilla de papel y fabricarse el suyo propio.
Un saludo a todos o como dirían mis compañeros, think that you!