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