Monday, May 17, 2010

Conclusión

A lo largo de este semestre se aprendió un nuevo lenguaje de programación. Se aprendieron nuevas técnicas del desarrollo de software. Se utilizo subversion para tener el código siempre disponible y se realizo un proyecto de un tamaño importante.

Se pudo ver como clojure es un lenguaje muy poderoso que requiere de mas tiempo para poder ser dominado. Y algo que todos nos llevamos es que nunca la primera solución que se nos ocurre es la ideal para el problema.

Sunday, May 16, 2010

Recetas de cocina


El conocimiento no vale si no se comparte, es una frase bastante sabia, ya que si uno se queda callado y no divulga su conocimiento, es como si este no existiera por que no vale.

Empezamos este post con esta reflexión, ya que en este caso vamos a compartirles algunas cosas que hemos encontrado y que nos han servido durante la realización de nuestro proyecto. Nosotros decidimos hacer este blog en español para que pudiera ayudar con la información que contiene a personas que hablen español y que tengan problemas en entender el ingles, o simplemente les guste mas su lenguaje.

A continuación unas “recetas de cocina”(por que se siguen los pasos y queda), que nos fueron bastante útiles

Serializar datos para poder mandarlos en un socket:

(defn serializar
"Convierte estructuras en strings"
[datos]
(binding[*print-dup* true]
(print-str datos))
)

Realizar un MessageDigest, en este caso MD5

(defn MD5
"Calcular el MD5 de ciertos datos”
[datos]
(let [md (doto (MessageDigest/getInstance "MD5"))]
(.update md (.getBytes datos)
(let [resultado (.digest md)]
(str-join "" (map #(Integer/toHexString (bit-and % 0xff)) resultado)))))

Obtener la documentacion con gen-html-docs
Hay que asegurarse que el archivo que deseamos tener tenga dentro de su namespace (:require clojure.contrib.gen-html-docs).

Ejemplo (ns ejemplo.ejemplo (:require clojure.contrib.gen-html-docs))

Dentro del REPL

(use 'clojure.contrib.gen-html-docs)
(generate-documentation-to-file “archivo.html” [ejemplo.ejemplo])

Generar un jar a partir de diferentes archivos en diferentes namespaces, incluyendo clojure.

Lo primero es tener el jar de clojure y clojure-contrib

Despues dentro de la carpeta donde estemos trabajando, crear una carpeta classes. Digamos que teníamos la carpeta proyecto, con los namespasces a, b. Ahora tenemos a, b y classes.

Tenemos dentro de la carpeta donde están a, b y classes el jar de clojure y el jar de clojure-contrib.
Nos aseguramos que todas las clases que queramos compilar tengan (:gen-class) en su namespace.

Corremos:

java -cp clojure-contrib.jar:clojure.jar:.:./a:./classes:./b clojure.main

Una vez dentro del REPL, compilamos cada archivo, digamos que dentro de a existe prueba y dentro de b prueba 2

Compilamos con:

(compile 'a.prueba)
(compile b.prueba2)

Y salimos del REPL

Es importante notar que alguno de los archivos debe tener una función (defn -main [] etc), donde los parámetros, son los parámetros que recibrecibirá nuestro jar desde la linea de consola

Ahora se necesita crear un Manifest.txt. Digamos que en prueba esta nuestro main, por lo tanto hacemos

Main-Class:a.prueba y lo guardamos como Manifest.txt

El siguiente paso es desempaquetar el jar de clojure, abriéndolo con cualquier programa que desempaquete .zip, y colocamos la carpeta clojure dentro de classes

Hacemos lo mismo con clojure-contrib, pero en vez de poner la carpeta clojure dentro de classes ponemos la carpeta contrib dentro de clojure.

Ahora en la consola corremos jar cmf Manifest.txt Nombre_de_nuestro_jar.jar a b clojure.

Esto nos generara un jar, el cual esta listo para ser usado en computadoras que tengan el jre instalado.

Imagenes en jar

Para que se pueda desplegar una imagen desde el jar, esta tiene que estar en la carpeta donde la va a llamar y esta a su vez dentro de jar.

Digamos que necesitamos un Imageicon. Para llamarlo usamos el siguiente codigo:

(ImageIcon. (ClassLoader/getSystemResource"Ruta_imagen"))

Esperamos que estos pedacitos de codigo les puedan ser útiles En un rato mas, les mostraremos la aplicación finalizada.

Soren Out


Finalmente... la interfaz

Para esta reunión, Gianfranco y yo estuvimos arreglando detalles con la interface, enfocado al "Look and Feel" de java, las ventanas seleccionadas para este punto fueron los de "Create" y del "Update". Para la fechas, agregamos JComboBox para año, mes y día; lo interesante resulta al momento de seleccionar un mes, ya que los días aparecen en relación a éste.

En el "menu bar", ahora tiene mas opciones activadas, ya que hay ocasiones que los usuarios se guían mas por la barra de herramientas, pretendemos ampliar la gama de posibilidades para que el usuario este cómodo.

Paso algo raro al momento de crear un string en base a los elementos seleccionados del JCombobox, extrañamente no los concatenaba y tuvimos que agregar un string vacío (""), únicamente así funcionó.

Realmente la parte poco amigable del diseño resulta cuando todo debe de quedar perfectamente centrado y alineado. Es lo que mas batalla nos dio, pero finalmente ha quedado listo.

-- Dev-it --


Saturday, May 1, 2010

Concurrencia y hashing


Hola a todos

En la junta del viernes definimos que haríamos exactamente con la concurrencia, para la cual utilizaríamos agentes del lado del servidor, ya que estos tienen un pool de threads y van actualizando a partir de una función. En nuestro caso ya tenemos una función llamada manager, donde esta el punto de choque, ya que ahí es donde se mandan todas las demás funciones a trabajar, lo que nos sirve para llamarlo desde la función que espera las conexiones en el socket.

Tambien encontramos que podría pasar que un cliente actualice y otro cliente en otro lado quiera actualizar, pero en nuestra implementan, el segundo cliente tendría una versión desactualizada. Para lograr solucionar esto, propusimos diversas alternativas: una era que los clientes actualizaran cierto tiempo pero esto no aseguraba que en realidad tuvieran versiones actualizadas al momento de interactuar con el servidor. Otra opción era actualizar siempre que se fuera a hacer una actualización, sin embargo esto generaría bastante overhead en la red, ya que no siempre va a estar desactualizado y hacer eso por vez, puede causar que se deteriore el desempeño del programa. Lo que propusimos y quedo aceptado, fue el usar una función de hash en los campos, para obtener el valor de estos, y así comparar el del cliente y el servidor, si son diferentes no se hace nada y se prosigue con la transferencia de datos y modificación de la base de datos. Si no son diferentes, el cliente actualiza a la ultima versión de los datos y entonces se ejecuta la actualización

Tuvimos que realizar un cambio en la forma en que el cliente manejaba sus datos, ya que por vez que quería realizar una acción, actualizaba sus datos, sin embargo no los tenia guardados en ningún lugar, lo cual no nos permitía usar las funciones de hash, por lo que decidimos usar una referencia, para poder mantener un estado en el cliente, dentro de un valor mutable. Esto ya esta reflejado en la revisión 45 de nuestra aplicación

Después les platicare de como resulta esto, ahora es tiempo de seguir trabajando.

Soren out.

Enviar estructuras por red en clojure



Hola a todos

(Este post se iba a llamar y antes de la concurrencia vino la red, sin embargo le cambiamos el titulo para que sea mas fácil de encontrar)

El vagabundo reportando desde los cuarteles de dev-it, donde se trabaja a toda marcha para tener listo el proyecto en la fecha de entrega. Actualmente atacamos el problema de la concurrencia, donde en la junta a pie que ocurrió el día de ayer se definió que se iba a hacer y mas importante el cómo. Pero antes quiero tomarme unos momentos para mostrarles un poco de como se realizo la parte de red de nuestro proyecto.

Estamos usando una conexión basada en sockets, los cuales van al servidor, y le piden el servicio que quieren, este a su vez interfacea con la base de datos y ejecuta lo que el cliente le pide para enviarle la información Lo importante que queremos compartir que fue una solución muy ingeniosa es el de como se pasa la información Se sabe que en sockets o se pasa en binario, o a un nivel mas grande de abstracción y se pasan strings, integers, etc. Pero en nuestro caso pasamos estructuras de datos hechas en mapas(los que van entre {} por si se confunden entre tantos tipos de datos útiles de clojure). El problema al que nos enfrentábamos era como pasar por la red esta estructura, la primera idea que tuvimos y que empece a implementar, como podrán ver en la revisión 43 y 42 del proyecto http://code.google.com/p/dev-it/source/detail?r=43 era destruir la estructura, pasarla y rearmarla en el lado del cliente. Muy eficiente a nivel de que no generaba overhead innecesario en la red, pero perdíamos tiempo en re ensamblar la estructura. El extranjero(Gianfranco) encontró una solución gracias a la ayuda que tuvo en el SHDH, como detallo en el post pasado, sin embargo dejo a todos en suspenso al no decir la solución, la cual detallare aquí:


(defn serialize
"Converts structures into strings"
[data]
(binding[*print-dup* true]
(print-str data))
)

Simple y sencillo. Segun el API de clojure la bandera/variable * print-dup* nos permite imprimir una variable de forma en que conserve su tipo para que al leerlo con read-string se pueda leer completa la estructura. Así pasamos de un describe de aproximadamente lineas a uno de 5. Para pasar los datos, simplemente se “imprimen” en el stream de salida y se leen con el read-string en el stream de entrada del otro lado. Decidimos dedicar un post especial para esto, ya que es una forma bastante interesante de atacar este problema, que permite programar mucho mas rápido este problema

Mas tarde, concurrencia

Soren out

Sunday, April 18, 2010

Super Happy Dev House Mexico City

Hola a todos los que siguen este blog. 8D

Les habla el extranjero (aka Gianfranco), reportándose después del SHDHMC. Este es mi primer evento de este tipo y decidí aprovecharlo para trabajar un poco en el proyecto.

Decidí que lo que intentaría sería implementar la parte de red del proyecto. Después de que un amigo me hablara de una opción para poder convertir una estructura (diccionario, vector, etc) a una cadena de caracteres me dispuse a probarlo.

Una vez que se podía convertir las estructuras a una simple cadena era mucho mas fácil pasarlas del servidor al cliente y viceversa. Entre los problemas mas grandes que hubieron:

1) Estaba el hecho de que al importar los archivos de servidor para convertirlos poco a poco en las versiones de red había que poner una bandera para que a la hora de importarlos no se ejecutara el servidor.

2) Otro de los problemas fue que por alguna razón no me dejaba hacer el bind hasta que reinicié la computadora. Esto solo ocurrió una vez al principio cuando todavía estaba experimentando con los strings.

Una vez que funcionó el select (a lo que estaba casi bailando de felicidad), hacer funcionar el create, update y delete fue muy fácil. Luego fue cuestión de ponerlo todo en el archivo client.clj y revisar que todo siguiera funcionando. =D

Fue un dia muy productivo y espero ir de nuevo a SHDHMC.


Wednesday, March 24, 2010

Avances del domingo

Saludos a todos =D

Algo tarde pero mejor que nunca. En esta ocasión vengo a contarles los avances y percances que tuvimos el domingo pasado. Nos reunimos Ana y yo(Gianfranco) para poder ver cómo cargar la información en la base de datos.

El problema que teníamos y que nos contó otro equipo, era que si creabas la JTable con los valores entonces ya no se podía modificar. Luego de experimentar y buscar mucho entendimos que para poder hacer funcionar la JTable teníamos que implementar el AbstractTableModel. Para lograrlo tuvimos que usar un proxy. Después el otro detalle que solucionamos fue convertir un mapa a un arreglo de 2 dimensiones que es lo que necesita el AbstractTableModel.

Una vez logrado eso generalizamos todo en una función que recibe los records(de una búsqueda por ejemplo) que se convierten a un modelo de ahí se cargan en la JTable. Al principio suponíamos que era algo muy difícil, pero una vez que funcionaba nos dimos cuenta que era fácil. ¡YAY!

Otro de los detalles que en este momento estamos solucionando y que no funciona tan bien, es el hecho que queremos poner un identificador a los registros para que a la hora de borrarlos se fácil.