17 diciembre 2008

Monitoreo de aplicaciones en Java

A través de la consultora en la que estoy trabajando estuve analizando en los últimos meses problemas de arquitectura y performance de una aplicación J2EE.

Durante esta tarea descubrí algunas herramientas incluidas en el JDK (a partir de la versión 1.5), que son de muchísima utilidad para encontrar problemas de performance.

El primer paso: ¿Que proceso del SO es el de nuestra aplicación?

La forma más sencilla de ver que una aplicación esta consumiendo más recursos de los que debe, es usar alguna herramienta del sistema operativo como el Administrador de tareas en Windows o top en Unix.

El problema es que si tenemos varios procesos Java cuesta distinguir cual es cual. Para facilitar esta tarea el JDK incluye una herramienta llamada jps (similar al ps de Unix), por ejemplo:

jps -lm
(-l muestra el main class usado, y -m muestra los argumentos pasados al main)

Monitorear la Virtual Machine

La VM incluye también servicios de JMX para monitorear su funcionamiento: uso de threads y memoria.

Hay dos herramientas para hacer esto: JConsole y VisualVM (incluida con en el JDK 6 a partir del update 10). La primera solo provee información mediante los servicios de JMX que expone la VM. Mientras que el segunda puede además proveer información de profiling más detallada.

Ambas permiten conectarse de forma automática a una VM local (siempre y cuando la VM sea de una versión 1.5 o superior). Pero también hay varias maneras de conectarse remotamente:

Mediante JMX

Es necesario activar primero el acceso remoto a los servicios de JMX. Si no interesa tener ningún tipo de autenticación la forma más sencilla es agregar a la VM los siguientes parámetros de inicio:

-Dcom.sun.management.jmxremote.port=[portnum]
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Luego simplemente hay que indicar el IP y puerto al iniciar JConsole.

Usando jstatd

jstatd es un servidor de RMI que expone información sobre las VMs corriendo en el host actual. Para usarlo hay que primero crear un archivo de policy para establecer los permisos de este proceso.

Una forma rápida de crear el archivo de policy es usar la herramienta policytool y crear un archivo que permita hacer todo (ejecutar policytool, luego Add Policy Entry -> Add Permision -> seleccionar All Permision -> Ok y finalmente guardar el archivo), por ejemplo:

all.policy:

grant {
permission java.security.AllPermission;
};

Una vez creado el archivo de policy, jstatd se inicia de la siguiente manera:

jstatd -J-Djava.security.policy=all.policy

En una larga línea de bash:
echo 'grant { permission java.security.AllPermission; };' > all.policy; jstatd -J-Djava.security.policy=all.policy

Una vez levantado jstatd, es posible usar VisualVM para conectarse con la VM.

Análisis post-mortem

A veces (especialmente en producción) no es posible monitorear la VM en real-time. Para esos casos hay muy buenos análisis que se pueden hacer sobre una "foto" de la ejecución.

Encontrar Leaks

El proyecto Eclipse tiene una herramienta excelente para encontrar leaks: Memory Analyser Tool.

Esta herramienta lee un memory dump y lo analiza, permitiendo por ejemplo ver que tipo de objetos ocupan mas memoria, o recorrer el grafo de alcance del GC.

Lo bueno es que el dump se puede hacer sin problemas en un VM corriendo en producción (lo malo es que el dump ocupa mucho espacio en disco). Hay varias formas de obtenerlo:

Usando jmap (incluido en el JDK 6):
jmap -dump:format=b,file=HeapDump.hprof pid

Pasarle un parámetro a la VM para que haga el dump en caso de un OutOfMemoryException:
-XX:HeapDumpPath=/path -XX:+HeapDumpOnOutOfMemoryError

También es posible obtener el dump en el JDK 1.4.2, usando:
-XX:+HeapDumpOnCtrlBreak
y luego haciendo: kill -3 pid

(en este caso, no es posible indicar el path donde va a parar el dump... se guarda con extensión .hprof en el directorio donde se inicio la JVM).

Una tercer forma de obtener el dump es usando JConsole accediendo al MBean: com.sun.management.HotSpotDiagnostic y ejecutando la operación dumpHeap (el primer parámetro es el nombre del archivo donde se hara el dump).

Encontrar problemas de Threading

Se puede hacer un thread dump de dos maneras.

Cuando se usa kill -3 pid el proceso de la VM imprime el thread dump en el standard output de la VM en ejecución (notar que kill -3 no mata el proceso, lo malo es que el standard output de la VM puede estar en cualquier lado dependiendo de cómo se inicio el proceso, o incluso perderse en la nada si no se re direcciono a un archivo).

La otra forma más conveniente es usar jstack pid./p>

Una vez obtenido el thread dump se puede usar TDA (Thread dump analyzer): Esta herramienta parsea el thread dump y muestra la información de una forma más conveniente.

La información más interesante que se puede sacar del thread dump, es ver que threads están a la espera de un monitor (en mi caso esta información me sirvió para encontrar un monitor loco en el método toString() de Timestamp... malditas globales: Nota al margen toString() de la clase Date y sus derivados usa un calendario global que esta protegido con u synchronized, por eso hay que tener cuidado, escribir a un log un date.toString() puede dar problemas de threads esperando por entrar en la sección critica… es preferible usar SimpleDateFormat)

Conclusiones

Bueno este fue un post bastante técnico y especifico en comparación a los que venia haciendo. Tenia ganas de escribirlo por una razón: es probable que en unos meses me olvide de todo esto :) por eso quería tener la información a mano en el Blog.

En mi caso la herramienta de análisis de memoria de Eclipse fue un "golazo"! Puede hacer el dump en producción y encontrar el leak en segundos.

17 febrero 2008

ACM Interactions

Por alguna alineación especial de los astros el volumen de Enero/Febrero del 2008 de ACM Interactions (la publicacion de ACM dedicada a interaction design) esta disponible gratis para bajar (las revistas de ACM por lo general requieren subscripción).
Bueno antes de que me olvide aca va el link. (en el lector online de la revista hay una opción para bajar el PDF)

Más sobre JUnit 4.4

En un post anterior, comente las nuevas caracteristicas de JUnit 4.4.

Ahi mecione que no le veia demasiado valor a los "Theories" que incorporó el framework. Debo adminitir que me equivoqué. Los estuve probando y ahora les veo dos cosas muy interesantes.

La primera es que es tipico tener casos donde hay una interfaz, luego una clase abstracta que implementa ciertos metodos y finalmente varias implementaciones. El problema que surgue con este esquema es: ¿Donde testeo los metodos que implementa la clase abstracta?. Mi solución a este problema siempre fue: o bien repetir los tests de estos metodos en los tests de unidad de cada clase concreta o bien usar un test abstracto y heredar los tests de las clases concretas de este test abstracto.

Los "theories" resuelven este problema de una forma muy elegante: cada clase concreta puede ser un "DataPoint" de un test con theories, y problema solucionado. Cuando se agrega una nueva clase concreta solo hay que agregarla como "DataPoint" (es una lastima que el meta modelo de Java no soporte el "allSubclasses" de Smalltalk).

Otra caracteristica que encontre importante es la de comunicación, usando la palabra "Theory" en lugar de test, se transmite muy bien la intención de "Programming as theory building".

Los unicos problemas que le veo a JUnit 4.x son: que todavía no tiene una buena integración con Eclipse, y que el uso excesivo de los import static es muy incomodo (estoy acostumbrado a usar organize imports asi que cada vez que tengo que usar uno de estos metodos estaticos que no use antes tengo que volver a escribir el import, horrible).

08 febrero 2008

Los prefijos "set" y "get" en Java son un dolor de bolas

Canilla

¿Para que lado se gira una llave de paso de una canilla... izquierda o derecha?

Es difícil responder a esta pregunta de forma instantánea. Uno se tiene que poner a pensar en como usa canilla, y quizás hasta hacer el gesto con la mano de como se gira la llave de paso. Sin embargo cuando nos vamos a lavar las manos, lo hacemos de forma inmediata, y ni siquiera tememos que pensarlo.

¿Por que pasa esto?

Por que la canilla en si misma tiene la información para utilizarla. Según Don Norman, en su libro “The Design of Everyday Things”, todas las cosas que usamos diariamente contienen una cantidad enorme de información. Información que no nos interesa retener de forma exacta en la cabeza, pero que tenemos presente a la hora de utilizarlas.

Es por eso que desde el punto de vista de usabilidad, las cosas bien diseñadas no requieren un manual de uso: el mismo objeto nos da información de como utilizarlo.

¿Y de que forma se nos presenta esta información?

Siguiendo con el libro de Norman: esta información se nos presenta por medio de affordances y restricciones (constraints).

En el caso de la canilla, la misma forma nos incita a girarla (affordance) y es la rigidez de la llave de paso nos dice: “para este lado no abre... proba para el otro” (constraint).

Estos constraints pueden ser físicos, como en el caso de la canilla. O bien culturales.

A simple vista pareciera que los constraints culturales son más “leves”, sin embargo pueden tan fuertes como los físicos, por ejemplo si tengo un muñeco para armar sé que la cabeza tiene cierta dirección (a menos que este armando un modelo de la chica de Poltergeist).

Playmobil

En los lenguajes de programación pasa mas o menos los mismo. Hay constraints “físicos”: si no uso la sintaxis correcta el programa no compila. Y constraints culturales, por ejemplo en Smalltalk o Java nadie usa nombres de clase en minúsculas.

Este blog post parte de la hipótesis de que en programación estas restricciones culturales a veces pueden influir en la forma en que pensamos los problemas.

Por ejemplo en Smalltalk, se suele tener la convención “cultural” de hacer que los métodos tengan nombres cuya escritura sea similar a un texto en ingles, por ejemplo:

client loginWith: credentials toServerAt: address.

En cambio si uno ve cosas de este estilo:

client setCredentials: credentials; setServerAddress: address; login.

Suena raro. Por lo que esta convención tiene un impacto en como esta diseñado el framework: uno pone más énfasis en la comunicación de la intención, que en los detalles de implementación.

Hecha toda esta introducción voy a ir al tema que le da titulo a este post.

JavaBeans

Entre las las “restricciones culturales” que existen los lenguajes de programación, identifico dos grupos:

  • Las que provienen de hacer mas legible el código
  • Las que provienen de una cuestión de implementación

En el caso de Java, entran en el primer grupo cuestiones como: las clases van en CamelCase, los paquetes en minúsculas, los métodos en minuculasMayusculas sin usar “_” como separador de palabras, etc.

Y en el segundo grupo cuestiones como poner el prefijo “set” o “get” si el método es un accessor a una variable de instancia.

Este uso de “set” y “get” se lo debemos principalmente al framework de JavaBeans.

Para los que no conozcan el framework de JavaBeans, les cuento un poco la historia:

Con la aparición de editores gráficos, muchas veces se hace necesario contar con metadata que permita manipular a los objetos gráficamente. El problema de esta metadata es que agrega una complejidad que suele ser bastante molesta: la metadata es importante para el framework, pero no para el problema que tratamos del modelar.

Por esta razón los diseñadores del framework, separaron la metadata de los objetos que modelan el problema. En el caso de JavaBeans, un editor que manipula objetos gráficamente puede utilizar la metadata proveniente de una clase que implementa BeanInfo.

Esta clase entre otras coas posee información sobre que atributos se pueden manipularse gráficamente.

El problema es que crear estas clases BeanInfo es bastante molesto. Por lo que los diseñadores del framework agregaron un shortcut: si no hay BeanInfo se asume que la clase sigue una convención de nombres (el “set” y “get”) para saber que métodos se utilizan para modificar el estado del objeto.

Luego la misma metadata fue utilizada para paginas web, con la intención de hacer editores gráficos. Y así fue como la convención de “set”, “get”, “is” se empezó a utilizar en todos lados. Hasta que finalmente, no importa si un objeto va a ser manipulado gráficamente o no: todos los desarrolladores en Java usan la convención del prefijo “set”/”get”.

Consecuencias del “set”/”get”

Sin embargo esta convención tiene sus consecuencias: uno empieza a pensar en los objetos como si fuesen estructuras de datos potenciadas.

Cualquier fanatico de objetos diria: un objeto no es una estructura de datos con métodos!

Pero entonces... ¿Cual es la diferencia?

Bueno desde el punto de vista de implementación uno puede ver a los objetos como si fuesen estructuras de datos con métodos. Al igual que uno puede ver a todos los sistemas computacionales como una gran maquina de estados.

El problema no es que este punto de vista sea erróneo, el problema es que no es un punto de vista útil para diseñar un sistema orientado a objetos. Ocurre lo mismo con las maquinas de estados: plantear todo sistema como maquina de estados es útil para utilizar herramientas de model checking, pero hace que el sistema sea más difícil de entender por un humano. (es análogo a lo que ocurre en matemática: si uno se pone a demostrar todo con una formalidad lógica exacta el problema se hace mucho más difícil de manejar).

Voy a mostrar lo que comenté con un ejemplo, si uno ve este código:

display(directory.getFiles());

Uno lee: “mostrar, directorio obtener archivos”.

En cambio si no ve:

display(directory.files()).

Uno lee literalmente: “mostrar archivos del directorio”.

La diferencia es sutil, pero ese “get” en el medio hace que uno piense en el objeto directorio como si fuese una estructura de datos con una variable files adentro.

A lo que quiero llegar con este largo post es que habría que eliminar de una vez por todas la convención de “set”/”get” de Java!

No aporta mucho desde el punto de vista de comunicación ya que es muy fácil por contexto darse cuenta si un método cambia el estado de un objeto, y resulta perjudicial para plantear problemas desde el punto de vista de orientación a objetos.

Fotos:
La foto de la canilla fue obtenida de esta dirección http://flickr.com/photos/cwalker71/1021798486
Y la del playmobil de: http://flickr.com/photos/eleftheriag/370683078
Ambas tienen licencia Creative Commons, y pertenecen a sus respectivos autores.

04 febrero 2008

JUnit 4.4 y Hamcrest

A partir de la versión 4.4 de JUnit se incorporo al framework un cambio que permite expresar los assertions de una forma más natural. Tomando algunos ejemplos del release notes:

assertThat(x, is(3));
assertThat(x, is(not(4)));
assertThat(responseString, either(containsString("color")).or(containsString("colour")));
assertThat(myList, hasItem("3"));

Este cambio me pareció más que interesante. Primero por que la consecuencia de modelar ciertos conceptos muy abstractos como el chequeo realizado en un assert (llamado Matching en el framework) se obtuvo una interfaz con más "intention revealing" e información. Por ejemplo este tipo de assert puede mostrar mejores mensajes de error:

assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
// ==> failure message:
// java.lang.AssertionError:
// Expected: (a string containing "color" or a string containing "colour")
//      got: "Please choose a font"

La otra consecuencia es que permite expresar más facilmente ciertos asserts que antes eran complicados, por ejemplo para chequear si una colección tiene ciertos elementos puede usarse directamente hasItems donde antes habría que crear una colección a parte y chequear por la inclusión de los elementos (o hacer un assert por elemento).

La buena noticia es que estos asserts especiales pueden utilizarse en versiones más viejas de JUnit ya que fueron "robados" de un proyecto llamado Hamcrest (ver tutorial).

Llevando la misma idea a Smalltalk

Si bien muchas expresiones son más simples en Smalltalk (debido al tipado dinamico y a los keyword messages) algo de este estilo:

assertThat(x, is(not(4)));

No queda de una forma linda:

self assertThat: x matches: (self is: (self not: 4))

Al principio pensé que aprovechando que en Smalltalk se puede "capturar" un DNU, podrían obtenerse expresiones similares. Por ejemplo al capturarse los DNUs para los selectors #assertThat:xxx:yyy:, determinar que Matcher utilizar en base a la porción "xxx:yyy:" del selector, luego el código quedaría asi:

self assertThat: x isNot: 4

Pero como podrán ver en el ejemplo en este caso el isNot no es una composición de Matchers, ouch!. (de todas formas estimo que is(not(4)) es equivalente a not(4)... si no la composición no me cierra, esta forma de hacer el "is not" debe ser solo por motivos de intention revealing, aunque no estoy con un Eclipse para poder comprobarlo).

La primer opción de crear los objetos directamente como en Java da un resultado que no queda tan expresivo, aunque es más simple y más flexible. 

Otra opción muy ala Smalltalk sería agregar metodos a Object para crear los Matchers (en lugar de usar la igualdad común y corriente), por ejemplo:

self assertThat: (x is: 4) negated

El problema de esta opción es que estos métodos para los Matchers tienen sentido solo en el contexto de los tests, por lo tanto agregarlos a Object sería una mala idea.

En fin, este tipo de "DSL Interno" como les llama Fowler (aunque yo prefiero llamarlos "truquitos sintacticos") tiene su particularidad en cada lenguaje. 

En Smalltalk las expresiones utilizando keyword messages y mensajes en cascadas son muy "lindas" para este tipo de cosas, pero en Java también los metodos static en conjunción con el "peligroso" import static, permiten usar Factory Methods para escribir expresiones "lindas".

La cuestión esta en si este tipo de assert agrega valor en Smalltalk. En Java yo creo que agrega mucho valor ya que la sintaxis del lenguaje hace dificil escribir cosas intention revealing y este me parece un lindo "hack" para lograrlas.

Otras caracteristicas de JUnit 4.4

Volviendo a JUnit, otra caracterisca robada de otro framework, es la capacidad de definir ciertos objetos que aplican a ciertos test (es decir definir explicitamente los "fixtures").

Por ejemplo es muy común escribir tests del estilo:

public void testResultWhenUserIsNotLoggedIn() // ....
public void testResultWithManagerUserSession() // ...
public void testResultWithGuestUserSession() // ...

No se si se capta la idea: cada test es para ciertos objetos (en este caso podrían ser sesiones de usuarios en diferentes roles).

Esta nueva caracteristica de JUnit, con el pomposo nombre de "Teorías", permite definir explicitamente los objetos y luego indicar mediante un "assumeThat" para caso aplica el test, seria algo asi:

@DataPoint private static Session nullSession = new NullSession();
public void testResultWhenUserIsNotLoggedIn(Session s) {
  assumeThat(session.notLoggedIn());
  // ....
}

Es decir los assumeThat actuan como predicados que indican que información corresponde al test.

Evidentemente esta caracteristica provee más información estatica sobre el test: un editor puede saber que "datos" se utilizan como entradas de los tests. 

Aunque no veo esta caracteristica con tanto entusiamo, me da la impresión que agrega mucho más complejidad al framework y no es tán facíl darse cuenta para que casos aplica cada test. Además por lo que vi en los ejemplos pareciera que las "Teorias" no están reificadas, eso genera que se usen anotations para cosas que se expresarian mejor de la manera "clasica".

Estos son mis "prejucios" sobre los Theories en JUnit 4.4... sería bueno ver comentarios de como esto funciona en un proyecto con muchos tests, o con "fixtures" complicados (los ejemplos en el sitio usan fixtures muy simples, la mayoría con tipos primitivos).

03 enero 2008

Boceto

Estoy tratando de hacerme de un habito de dibujar seguido, con el objetivo de mejorar la forma en que dibujo. Por ejemplo quisiera lograr mucha más soltura y poder captar cierto “ritmo” en las expresiones corporales/faciales (la capacidad de observar y plasmar esas “cositas” es lo que más me asombra de los dibujantes grosos).

Acá va el primer boceto del año:

Boceto

El boceto en si tiene muchísimos errores: en los ojos, la boca es demasiado chica, etc, etc. Sin embargo pude hacerlo, escanearlo y subirlo al blog en una hora y media... eso para alguien que tarda días en un dibujo es todo un avance :-D

02 enero 2008

2008: Año nuevo... diseño nuevo

Screenshot del nuevo diseño

Como bienvenida al 2008 he decidido modificar el diseño del sitio, por uno más simple, y algo mejor (creo) a la hora de leer posts largos.

Espero les guste y avisenme si se ve mal o algo asi.

 

¡Feliz 2008 para todos!

 

Diego.-