martes, 19 de enero de 2010

MySQL Workbench: Una opción para crear tus diagramas ER



Hace un tiempo estuve "googleando" para encontrar alguna herramienta gratuita para diseñar diagramas de entidad relación (ER) y extrañamente no pude hallar ninguna rápidamente. De hecho ni siquiera me tomé la molestia de descargar algunas de las aparentemente "freeware" que estaban disponibles porque no me daban buena espina.

Un día de estos buscando la página para descargar MySQL Admin, el cual es un cliente gestor de bases de datos MySQL, me di cuenta que existia otra herramienta de la misma gente de desarrollo: MySQL Workbench. Esta herramienta tiene varias utilidades que no he explorado bien aún pero me llamó la atención que tiene justo lo que andaba buscando. MySQL Workbench permite no solamente diseñar los diagramas desde cero, sino que también provee la posibilidad de aplicar ingenieria inversa para generar el diagrama a partir de una base de datos existente.

Esta opción de ver los diagramas actualizados con la BD era algo que resentía no tener en MySQL y que por el contrario siempre ha sido parte de MS SQL Server, al menos desde que comencé a usarlo en la versión 2000. Sin duda MySQL junto con las herramientas que lo acompañan cada vez resulta ser una opción más competitiva y robusta para el desarrollo de base de datos. Ya no es como en los tiempos en que el profesor nos decía que si necesitabamos una BD sin mucha complejidad usaramos MySQL.

viernes, 8 de enero de 2010

¿Recargar o no recargar?

He notado que varios compañeros de equipo configuran en Tomcat la aplicación en la que trabajamos con el atributo "reloadable" en "true".

<Context path="/miaplicacion" reloadable="true" docBase="C:\MiAplicacion" />

Este atributo causa un comportamiento que para mi es bastante incómodo a la hora de estar desarrollando y haciendo pruebas con la aplicación localmente. Si uno tiene arriba el tomcat y desea modificar el código un poco para ver si esa pulga que tenemos se resuelve, uno tiene que esperar para arrancar de nuevo el servidor ya que cualquier cambio al código de la aplicación produce automáticamente un reinicio del servidor.

Curiosamente la página de Apache Tomcat recomienda habilitar esta opción para desarrollo:
"Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. This feature is very useful during application development..."
Supongo que debe ser útil si uno constantemente actualiza el código desde un repositorio central y necesita que la aplicación sea refrescada con los últimos cambios. La verdad no estoy seguro qué es lo que se gana exactamente, pero en mi experiencia es preferible no habilitarla pues es cansado sobre todo si la aplicación requiere de un tiempo significativo para reiniciar.

Cuando dejamos el atributo reloadable="false" nuestro código con solo ser guardado podrá reflejar los cambios en la aplicación en vivo con la excepción de que los cambios no sean sobre la "firma" de la clase. Si se cambian miembros de clase o los parámetros de entrada o salida de cualquier método, la aplicación forzamente tiene que ser reiniciada.

Esa ha sido al menos mi experiencia con Eclipse, quizás algún otro IDE se comporte diferente pero supongo que debe ser una norma general al tratarse de configuración de Tomcat. Mi recomendación es apagar esta opción y si notan que un cambio no se está viendo reflejado o la aplicación se comporta extraño, entonces manualmente se reinicia el servidor.

lunes, 4 de enero de 2010

Excepciones Amigables con las Bitácoras

Es usual para un programador novato y con prisa, resolver el tema de las excepciones simplemente suprimiéndolas o atrapándolas para únicamente registrarlas en bitácoras (logs) y lanzarla hacia arriba para repetir el proceso en las clases subsecuentes. Puedo afirmar esto porque yo mismo solía manejar las excepciones de esta manera. Uno puede pensar al principio que esto es lo más considerado, "loguiemos por si acaso".


public class A {
public void callB() throws Exception{
try {
new B().doSomething();
} catch (Exception exception) {
exception.printStackTrace();
throw Exception;
}
}
}

public class B{
public void doSomething() throws Exception {
try {
// Code potentially exception throwing.
} catch (Exception exception) {
exception.printStackTrace();
throw Exception;
}
}
}

Esta es una práctica común que parece inofensiva al principio en las etapas de desarrollo, pero no es hasta que nos encontramos analizando un problema de la aplicación corriendo en producción que nos damos cuenta de la mala idea que es tirar excepciones a lo loco. Cuando tenemos que investigar un problema de la aplicación que require ir a buzear en los archivos de bitácora, las múltiples apariciones de una sola excepción en varias clases produce un colocho mental para aquel que tiene que interpretar los registros de excepciones.

Además esto agrega ruido para cualquier actividad de monitoreo de las bitácoras. La excepción es multiplicada por el número de clases que invocan el método originador de esta, y cada clase no agrega ninguna información adicional de relevancia. Este confeti de excepciones crea la percepción de que el problema mostrado por la excepción es más grave de lo que parece. Esto dificulta la tarea de dirigir los esfuerzos al problema real.

Sugiero dos opciones para mejorar esto dependiendo de las necesidades de la aplicación:

1. Registrar en bitácoras solamente en la capa donde la excepción es producida y arrojar una excepción de tipo RuntimeException. Una excepción de tipo RuntimeException no necesita ser atrapada.

public class B{
public void doSomething() throws Exception {
try {
// Code potentially exception throwing.
} catch (Exception exception) {
exception.printStackTrace();
throw new RuntimeException(exception);
}
}
}

2. Lo otro que podemos hacer, sobre todo si las capas de arriba necesitan enterarse de que una excepción ocurrió, es crear nuevas excepciones (conocidas también como "wrappers") acuerdo con un grupo de categorias que facilitan la lectura de las bitácoras. En el siguiente código muestro un ejemplo con dos excepciones personalizadas: una cuando la culpa recae en el usuario debido a una mala especificación de los parámetros, y otra para encapsular las excepciones que se deben a una invocación remota.

public class ConfigurationException extends Exception {

}

public class RemoteServiceException extends Exception {

}


public class B{
public void doSomething(String mathFormula) {
try {
// Code to execute formula.
} catch (Exception exception) {
throw new ConfigurationException(exception);
}
}

public void doSomethingRemotely() {
try {
// Code to read Web Service.
} catch (Exception exception) {
throw new RemoteServiceException(exception);
}
}
}

public class A {
public void callB() {
try {
B b = new B();
b.doSomething("filePath");
b.doSomethingRemotely();
} catch (ConfigurationException configurationException) {
System.out.println("There was a configuration error!");
exception.printStackTrace();
} catch (RemoteServiceExceptionremote) {
System.out.println("There is no connectivity with remote services!");
exception.printStackTrace();
}
}
}


Al agregar otro nivel de abstracción ayudamos en las actividades de CSI (escena del crimen), especialmente cuando la gente que le toca esto no es la misma que la gente del equipo de desarrollo.