Evolución de las versiones de JAVA y .NET a lo largo del tiempo

Timeline JAVA vs DOTNET
Suelo tomar entrevistas a desarrolladores, y una pregunta que solía hacer hace unos años, era que me cuenten las diferencias que había (por ejemplo) entre las versiones de JAVA 1.4 y 5.0. Era un buen ejercicio como para repasar algunas de las características más usadas y además me parecía interesante ver como los candidatos me "presentaban" esas características. Los programadores más experimentados solían poner una cara de "al fin agregaron esto o esto otro", y los que no venían muy bien o no les interesaba, dejaban pasar cosas importantes sin ni siquiera mencionarlas.
Me pasaba algo parecido con la plataforma .NET de Microsoft, no se porque, a mi me pareció siempre interesante ver que cosas nuevas van agregando a los lenguajes y herramientas de trabajo que usamos todos los días a lo largo del tiempo.
Pensando un poco en todo eso, me propuse hacer un repaso de las características más sobresalientes de las dos plataformas, pero para no hacer tan aburrida la cosa, armé un timeline:



Las imágenes son clickeables y agregué en cada release algunas notas acerca de las características más importantes de cada uno.
Opinan que los releases son lo suficientemente frecuentes? Que versión de cada plataforma les pareció más interesante?

Fuente: Wikipedia

Como loggear el SQL que genera Hibernate con los parámetros de la consulta

Log4JDBC
Hace poco me vi en la necesidad de analizar los queries que genera Hibernate, pero la información que estaba necesitando era relacionada a los valores de los parámetros que recibía mi query.
Hibernate posee un par de opciones bastante conocidas para mostrar el SQL generado, una es agregar el parámetro "hibernate.show_sql" con valor true, en la configuración del SessionFactory. Como acotación al margen, existen otros dos parámetros interesantes: "hibernate.format_sql", el cual si el valor es verdadero, formatea la sentencia SQL generada (útil cuando analizamos consultas complejas), y la otra es "hibernate.use_sql_comments", que cuando tiene el valor verdadero agrega a las sentencias, comentarios relevantes (ej.: se está persistiendo la clase com.xxxx.yyyy.ClaseZZZ). Este enfoque tiene la contra de que se usa la salida estándard (no es compatible con frameworks de logging como log4j) y además no muestra los parámetros utilizados para ejecutar la consulta.
Otra opción es configurar el output mediante log4j. En este caso es necesario activar el logger "org.hibernate.SQL". Luego de hacerlo, hibernate comenzará a mostrar las líneas por nuestros appenders configurados, lo cual es mejor que el escenario anterior, pero sigue sin mostrar los parámetros. Sin embargo existe otro logger, el cual si permite mostrar esta información: "org.hibernate.type". El problema es que si tenemos varios parámetros, los va a mostrar en muchas líneas:

Hibernate: INSERT INTO transactions (CHANGE, CLOSE, DATE, OPEN, CURRENT_ID, VOLUME) 
VALUES (?, ?, ?, ?, ?, ?)
15:33:07,243 DEBUG FloatType:133 - binding '10.0' to parameter: 1
15:33:07,243 DEBUG FloatType:133 - binding '1.2' to parameter: 2
15:33:07,243 DEBUG DateType:133 - binding '30 December 2009' to parameter: 3
15:33:07,259 DEBUG FloatType:133 - binding '1.4' to parameter: 4
15:33:07,259 DEBUG IntegerType:133 - binding '12' to parameter: 5
15:33:07,259 DEBUG LongType:133 - binding '344444' to parameter: 6

Por lo tanto me dispuse a buscar otra solución, que de paso me sirviera para mostrar todas las sentencias SQL que se vayan generando, incluso, porque no, otras que no provengan de Hibernate mismo.
Me encontré con el proyecto Log4JDBC, el cual era más o menos lo que estaba necesitando. Luego de analizarlo me encontré con el problema de que no funciona muy bien con aplicaciones que usan pooles de conexiones provistos por el application server (en mi caso Tomcat), y era complicado de configurar para que funcione correctamente.
Continuando la búsqueda me encontré con un fork: Log4JDBCRemix, que si bien, advierten de ser bastante experimental, funciona de maravillas. La diferencia con Log4JDBC original, es que es más amigable a Maven, y además más simple de configurar, porque funciona como un wrapper de un datasource.
A grandes rasgos, para hacerlo andar es necesario hacer lo siguiente:

1) Agregar la dependencia Maven:

<dependency>
  <groupId>org.lazyluke</groupId>
  <artifactId>log4jdbc-remix</artifactId>
  <version>0.2.7</version>
</dependency>

2) Si se usa spring, agregar un bean que funcione como indirección al verdadero datasource:

  <bean id="dataSourceSpied" class="...">
    <property name="driverClass" value="${datasource.driverClassName}"/>
    <property name="jdbcUrl" value="${datasource.url}"/>
    <property name="user" value="${datasource.username}"/>
    <property name="password" value="${datasource.password}"/>
    ...
  </bean>

  <bean id="dataSource" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
    <constructor-arg ref="dataSourceSpied" />
  </bean>

3) Configurar que mostrar finalmente en el log (en mi caso, solo necesitaba la sentencia con los parámetros reemplazados):

log4j.logger.jdbc.audit=FATAL
log4j.logger.jdbc.resultset=FATAL
log4j.logger.jdbc.resultsettable=FATAL
log4j.logger.jdbc.sqlonly=DEBUG
log4j.logger.jdbc.sqltiming=FATAL
log4j.logger.jdbc.connection=FATAL

Al momento de usar el aplicativo, vamos a poder ver en nuestro archivo de log, todas las sentencias SQL logueadas con los parámetros correspondientes, reemplazados en la misma línea:


29.07.2013 23:49:05 DEBUG (Slf4jSpyLogDelegator.java:232) -  org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
5. select groups0_.id_user as id2_3_1_, groups0_.id_group as id1_1_, group1_.id_group as id1_1_0_, 
group1_.creation_date as creation2_1_0_, group1_.last_modification_date as last3_1_0_, group1_.creation_user 
as creation4_1_0_, group1_.last_modification_user as last5_1_0_, group1_.name as name1_0_ from 
public.groups_users groups0_ inner join groups group1_ on groups0_.id_group=group1_.id_group 
where groups0_.id_user=45 
29.07.2013 23:49:06 DEBUG (Slf4jSpyLogDelegator.java:232) -  org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
6. select roles0_.id_group as id1_1_1_, roles0_.id_role as id2_1_, role1_.id_role as id1_2_0_, 
role1_.creation_date as creation2_2_0_, role1_.last_modification_date as last3_2_0_, role1_.creation_user 
as creation4_2_0_, role1_.last_modification_user as last5_2_0_, role1_.name as name2_0_, role1_.id_super_role 
as id7_2_0_ from public.groups_roles roles0_ inner join roles role1_ on roles0_.id_role=role1_.id_role 
where roles0_.id_group=44 

Luego de usarlo, me enteré de que existe un nuevo proyecto, denominado log4jdbc-log4j2, que posee todas las mejoras de Log4JDBCRemix, y algunas más.

Maven: Como cambiar la versión de mi proyecto

Una de las quejas que suelo escuchar con respecto a Maven, es acerca de lo complicado que puede ser mantener las versiones de nuestros proyectos y componentes, actualizadas. Es verdad, si uno intenta hacerlo manualmente (es decir tocando "a pata" los pom.xml), es bastante engorroso y error-prone.
Hasta hace un tiempo existía una manera de, por ejemplo, incrementar la versión de todos los componentes, usando el plugin Release de Maven, pero ese plugin les da miedo a todo el mundo (es uno de los plugins más potentes y complejos).
Otra manera que he visto que se ha usado bastante, de mantener las versiones, es usar variables definidas dentro de los pom.xml padre, las cuales se replican en todos los pom.xml hijos. Si bien esta manera parece a primera vista, cómoda y elegante, si la ubicamos dentro de un contexto de releases frecuentes, involucrando a servidores de integración y sobre todo, al plugin de Release, termina siendo un problema, ya que no conozco manera de que dicho plugin "entienda" esas variables.
Digamos, pasando en limpio: es una forma más simple de seguir toqueteando los pom.xml de forma manual. Pero sigue siendo lo mismo.
Otro problema que tiene el enfoque anterior es que si estamos visualizando un pom.xml hijo, no sabemos cual es la versión actual, no nos queda otra que "subir" al pom padre y verlo ahí. De esto se deriva, de que si conseguimos ese pom.xml de algún artefacto, tampoco a primera mano, no tenemos forma de saber que versión es.
Corolario: La versión siempre debería estar presente en los pom.xml, el uso de variables para esto no es una buena idea.
Esto nos lleva al principio, como podemos hacer para trabajar con las versiones de los pom.xml, sobre todo cuando los proyectos son cada vez más y más grandes?
Y esto es solo la punta del iceberg, no hablamos acerca de, por ejemplo, como trabajar con las versiones de las dependencias de nuestros proyectos.
Ejemplo: pasaron 2 años de que nuestro proyecto está funcionando, y queremos mantener actualizadas las versiones de las dependencias, como hacemos? investigamos una por una cual es la última versión y vamos incrementando las mismas en cada sección dependencies de cada pom? ... y que pasa si nuestro proyecto tiene 50 modulos diferentes? como hacemos para incrementar las versiones de todos de forma simple?
Lo mismo para los plugins de maven que estamos usando ... en fin, debería existir algo para lidiar con estos temas, no?

Maven Versions Plugin

Por suerte hoy en día existe un buen plugin para trabajar con las versiones de nuestros proyectos. Este plugin tiene muchos goals, en los cuales destaco los siguientes:

  • versions:display-dependency-updates: Muestra por pantalla las nuevas versiones que existen en los repositorios que usamos, de cada una de las dependencias de nuestros proyectos.
  • versions:display-plugin-updates: Idem anterior, pero de los plugins de maven que utilizamos.
  • versions:update-parent: Actualiza la versión de nuestro "pom padre" para que apunte a la última versión disponible. Esto es muy útil si contamos con un "super pom" en nuestra organización con definiciones comunes a todos los proyectos.
  • versions:set: Este es el goal más interesante y más útil: lo que hace es justamente cambiar la versión de nuestro proyecto a nivel global. Es decir, si los componentes de nuestro proyecto tienen dependencias entre sí, las mismas también se actualizan.
  • versions:use-releases, versions:use-next-releases y versions:use-latest-releases: sirven para reemplazar las versiones snapshots por releases, incrementar al próximo release o directamente reemplazar las versiones por el último release disponible
  • versions:use-next-snapshots y versions:use-latest-snapshots: Lo mismo que lo anterior pero con SNAPSHOTS
  • versions:commit y versions:revert: Permiten implementar todos estos cambios de forma pseudo-transaccional, es decir, si no estamos conformes con los cambios (o el proyecto no compila, o no corre) podemos volver a las versiones originales de los pom.xml
En fin, existen otros goals más, pero con estos ya se puede trabajar bastante bien con versiones de proyectos grandes de forma segura y rápida.
Se animan a usarlo?