Lo que no se sabe expresar, es que no se sabe.
Friedrich Engels

Archivos en la categoría Implementación

JSF Tag – converDateTime

jsf-logoLa etiqueta (taglib) de JSF convertDateTime aplica por defecto la zona horaria en la que se está ejecutando, por lo que cuando es ejecutada en España (que ahora estamos en la zona horaria GMT+2) lo que hace es restar 2 horas a la hora  que le es informada.

Es decir, ejecutando el siguiente código en España e informando user.createdOn como “01/01/2013 12:00:00″ :

1
2
3
<h:outputText value="#{user.createdOn}">
    <f:convertDateTime pattern="dd/MM/yyyy HH:mm:ss" type="both" />
</h:outputText>

se pintará en pantalla “01/01/2013 10:00:00″. Pero lo que es peor, en Portugal (está en la zona horaria GMT+1) pintaría “01/01/2013 11:00:00″ (creo, no me he desplazado a Portugal para probarlo :P ).

Y lo que es peor, si estás desarrollando en España y finalmente tu código se despliega y ejecuta en otro país, el resultado será….

Para solucionar esto (ñapa) en España podemos poner la zona horaria en el código:

1
2
3
<h:outputText value="#{user.createdOn}">
    <f:convertDateTime timeZone="GMT+2" pattern="dd/MM/yyyy HH:mm:ss" type="both" />
</h:outputText>

Aunque lo suyo sería que timeZone fuera una variable más a informar desde el servidor, porque sino cuando por ejemplo registremos un evento en el servidor persistiendo new Date(), al visualizar esa fecha se visualizará incorrectamente en clientes que no estén en la misma zona horaria que el servidor, complicando (innecesariamente) una lógica tan habitual como formatear una fecha.

¿Por qué no me gustará ningún código de Sun? ¿Por qué no respetaré las certificaciones de Sun?

 

Pantallazos de tu navegador

Todo evoluciona, hasta tomar pantallazos del contenido de tu navegador, se acabó el “Imprimir Pantalla” e ir luego al MS Paint a retocar, poner flechitas y recortar la imagen.

Awesome ScreenShot es una extensión gratuita tanto para Firefox como para Chrome y Safari para tomar pantallazos del contenido de tu navegador de una forma sencilla, elegante y potente.

Sin duda es una herramienta que mejorará la comunicación entre los usuarios (es que no me funciona cuando pincho el botón!) y los desarrolladores.

Subversive vs Subclipse

svnCuando me instalo un nuevo entorno de trabajo con Eclipse, siempre dudo qué plugin de código abierto de SVN instalarme (igual que me pasa con MAVEN), si instalarme Subversive de Polarion o instalarme Subclipse de Tigris (referencia en el mundo SVN), ambas soluciones muy similares funcionalmente, respaldadas por una gran comunidad y muy maduras. Y esta duda es bastante popular y antigua.

Sin embargo hay 3 razones por las que Subclipse brilla más que Subversive:

  • Están más involucrados en la evolución de la tecnología SVN.
  • Es significativamente más sencillo realizar un merge.
  • Soportan mejor cambios externos realizados por otros clientes SVN o directamente la línea de comandos.

La segunda razón sí que la considero suficiente para decantarme por Subclipse ya que hacer un merge es el punto más débil de SVN frente a GIT.

Transacciones ACID vs BASE

Las transacciones deben cumplir con el acrónimo ACID para ser confiables:

  • Atomicity, all or nothing, if one part of the transaction fails the entire transaction fails. Required when there is more than one Resource Manager. Example of two phase commit, marriage, both partners must return ok.
  • Consistency, any transaction will bring the database from one valid state to another. The bride can not become married to another broom after her ok if her broom fails and another one gives ok.
  • Isolation, can be executed concurrently but appear to execute serially.
  • Durability, when a transaction commits its result remains and must survive failures.

Sacado de la charla “Transactions: Over Used or Just Misunderstood?“, de Mark Little de JBoss en InfoQ.

Sin embargo, el teorema de Brewer nos condena a convivir con el fallo si queremos escalar nuestro sistema, para lo cual utilizamos transacciones que se conforman con que eventualmente nos encontraremos en un estado consistente y con ofrecernos respuestas aproximadas, cumplen con el acrónimo BASE:

  • Basic Availability
  • Soft-state
  • Eventual consistency

Copiar vs Duplicar objetos en Java

Java tiene gravísimos puntos oscuros desde sus orígenes, debido a que la API y el lenguaje están muy orientados a la implementación de la JVM y a la compatibilidad hacia atrás en lugar de orientarse a facilitar un lenguaje claro y sin ambigüedades.

Baste decir que cuando hablamos de J2EE no hablamos de “Java v2 Enterprise Edition” sino de “Java v1.2 Enterprise Edition“, pero todo el mundo (incluido yo) utiliza J2EE en lugar de simplemente JEE o J7EE (para referirnos a la versión 1.7 que es la actual de Java). Por cierto, cuánta falta hace que llegue por fin una versión 2.0 de Java!!!

Una de estas áreas de mejora es el mal uso de un concepto tan común como “duplicar” un objeto. La mayoría de las pesonas que leen este código,

1
2
3
Person personA= new Person();
personA.setName("Juan");
Person personB = personA;

piensan que personB es una copia de personA, dos objetos diferentes pero con los mismos valores, porque los humanos interpretamos la línea 3 como “Crear un nuevo objeto del tipo Person llamado personB que inicalizamos con los valores que tiene el objeto llamado personA”, o simplemente decimos “Copiar personA a un nuevo objeto del tipo Person llamado personB” pero queremos decir “Duplicar” en lugar de copiar.

Sin embargo Java se comporta de un modo diferente al esperado ya que la JVM interpreta esa línea de diferente forma. Si ahora realizamos un cambio en personB, comprobaremos asombrados cómo personA también ha cambiado!!!

4
5
personB.setName("Luisa");
//En este punto personA.getName() devolería "Luisa" y no "Juan".

¿Por qué? Porque lo que realmente significa para la JVM la conflictiva línea 3 anterior, es “Crear una nueva variable del tipo Person llamada personB y asginar la misma referencia que tiene la variable personA“, o simplemente “Copiar la referencia (y no el contenido) de personA en una nueva variable del tipo Person llamada personB“. El resultado es que tenemos dos variables apuntando a una única referencia (espacio en memoria) en lugar de dos variables independientes con sus respectivas y diferentes referencias (espacios de memoria). Así, cuando una de las dos variables cambia, cambian las dos. Sí, Java se orienta más a punteros que a objetos, que es más útil en programación a bajo nivel y para ahorra unos bits; no en vano Java se basó en C.

Entonces, Java no facilita una funcionalidad para duplicar objetos?!?!?! Java ofrece un interfaz Clonable, pero no su imlementación. Ocurre lo mismo para comparar dos objetos o comprobar si dos objetos son iguales o imprimir los valores de un objeto, te obliga a escribirte tu propia implementación para estas funciones de uso común, más común (para un desarrollador) que las interpretaciones estándares, ralentizando el desarrollo al escribir código de poco valor añadido y propenso a los bugs pero sobre todo complicando el mantenimiento ya que tiene que evolucionar al tiempo que evoluciona el negocio.

O utilizar implementaciones genéricas que son peligrosas.

Duplicación de objetos genérica

Podemos implementar nuestra propia solución genérica para solucionar esta laguna de Java, o podemos utilizar soluciones ya existentes. Así org.apache.commons.beanutils.BeanUtils parece ofrecernos la solución:

Person personB = null;
try {
	personB = (Person) BeanUtils.cloneBean(personA);
} catch (Exception e) {
	e.printStackTrace();
}

En este caso funcionaría, y ahora al volver a ejecutar un cambio en personB no cambiamos personA.

Pero qué pasa si el objeto Person tiene a su vez otros objetos, como por ejemplo un objeto User?

@Test public void duplication2Test2 () {
	User userA;
	Person personA, personB;
	personA = new Person();
	personA.setName("nameA");
	userA = new User();
	userA.setUsername("usernameA");
	personA.setUser(userA);
	personB = personDuplication.duplication2(personA);
	personB.setName("nameB");
	personB.getUser().setUsername("usernameB");
System.out.println("duplication1Test - personA.name = " + personA.getName());
System.out.println("duplication1Test - personB.name = " + personB.getName());
System.out.println("duplication1Test - personA.user.username = " + personA.getUser().getUsername());
System.out.println("duplication1Test - personB.user.username = " + personB.getUser().getUsername());
	Assert.assertEquals(personA.getName(), "nameA");
	Assert.assertEquals(personB.getName(), "nameB");
	Assert.assertEquals(personA.getUser().getUsername(), "usernameA");
	Assert.assertEquals(personB.getUser().getUsername(), "usernameB");
}

Este Test falla. La razón es simple, BeanUtils duplica las variables primitivas y las variables de tipos de Java como Boolean, Integer o String (que es la que se utiliza en el ejemplo), pero en lugar de duplicar los objetos que nosotros implementamos (como el usado en el ejemplo User) está copiando su referencia.

Duplicación profunda de objetos genérica

Una forma sencilla es serializar nuestros objetos y desearializarlos en nueva instancia, para lo que podemos utilizar org.apache.commons.lang.SerializationUtils. La parte negativa de esta solución es que nuestros objetos deben ser serializables (implementar el intefaz Serializable), y también todos los objetos que los componen, y también todos los objetos que componen a estos, y también… por lo cual es una solución con peligros de cara al mantenimiento evolutivo.

Por fin, la siguiente implementación pasaría el test anterior:

public Person duplicationPerson(Person personSource) {
	Person personTarget = null;
	try {
		personTarget = (Person) SerializationUtils.clone(personSource);
	} catch (Exception e) {
		e.printStackTrace();
	}
	return personTarget;
}

Lo podríamos hacer más genérico sustituyendo el tipo Person por Serializable. Más potencia, más peligro.

Comenta