lunes, 27 de diciembre de 2010

2010: El fin de una etapa

Este año que ha terminado ha sido extraño y agridulce en lo que a acontecimientos y efemérides se refiere.

En el pasado 2010 se han cumplido 25 años desde que se registró el primer dominio .com (symbolics.com). Aquél año de 1985 se registraron 7 dominios. Hoy hay registrados más de 80 millones. En cuanto a los dominios .es, comenzaron a registrarse en el año 1997 y hoy, dominios.es (anterior ES-NIC) cuenta con más de 1.200.000 dominios registrados.

También ha sido el cumpleaños de Java, ya que según su creador, fue hace 15 años cuando nació Java, si bien la primera versión se publicó en 1996.

Decía Unamuno que el progreso consiste en renovarse. Sea ésa la última causa o sea por causas pecuniarias más prosaicas, el caso es que este año 2010 ha sido el fin de Sun Microsystems, tras la confirmación de compra que se produjo finalmente por estas fechas el año pasado. Esta compra ha producido una preocupante desbandada de personas de esencial relevancia en las filas del antiguo Sun, ahora Oracle. Desde el propio CEO de Sun, Jonathan Schwartz, pasando por Tim Bray (coinventor del XML) hasta incluso el mismísimo James Gosling (creador de Java), la lista no ha cesado: Eduardo Pelegri (lider de la especificacioń Java EE, padre de JSP, y responsable de Glassfish), Simon Phipps (Sun's Chief Open Source Officer), casi todo el equipo de OpenOffice.... SunOracle ha perdido un enorme valor humano. Se diría que Oracle tiene una filosofía con un enfoque totalmente diferente, en lo que a su postura con el FOSS e innovación se refiere... ejem.

En sus 28 años de vida como empresa independiente (de momento Oracle mantiene la marca) Sun ha sido sinónimo de innovación, seriedad, escalabilidad y grandes sistemas. El procesador SPARC (la primera arquitectura RISC-II implementada comercialmente), el sistema de ficheros NFS, el Sistema Operativo Solaris (con ZFS, en su versión 10), Java (JSE, JEE, y resto de estándares asociados) han sido innovación directa de Sun Microsystems y legado tecnológico sobre el cual se han basado decenas de avances actuales hoy día.

Tras la absorción de Sun por parte de Oracle, el futuro de productos de código abierto como Glassfish, MySQL, Java, etc, es una incógnita, como ya comenté en un anterior artículo. Comienza a partir de aquí una nueva etapa para las tecnologías Java.

Veremos qué nos depara 2011.

¡Feliz año nuevo a todos!

jueves, 9 de diciembre de 2010

Las 8 falacias de la informática distribuída

En 1994, Peter Deutsch, uno de los miembros originales de Sun Microsystems, afirmó que arquitectos, diseñadores, y programadores de aplicaciones distribuidas a menudo solían asumir 7 supuestos que, en última instancia, resultaban falsos, poniéndose de manifiesto en forma de fallos del sistema, reducción sustancial en el ámbito de aplicación del sistema, o en grandes gastos imprevistos necesarios para rediseñar el sistema de forma que pueda cumplir con sus objetivos originales. En 1997, James Gosling (creador de Java) añadió un octavo supuesto.

Esas hipótesis son conocidas conjuntamente como Las 8 falacias de la informática distribuída o las 8 falacias de los sistemas distribuídos (8 fallacies of distributed computing):

  1. La red es confiable
  2. La latencia es cero
  3. El ancho de banda es infinito
  4. La red es segura
  5. La topología no cambia
  6. Hay un administrador
  7. El costo del transporte es cero
  8. La red es homogénea



Explicar cada una de las falacias (explicar por qué lo son) es bastante obvio. De hecho, llama la atención la adición de la falacia nº 8 en 1997 cuando realmente la heterogeneidad no era ni la centésima parte de lo que es ahora, con decenas de tipos de redes y dispositivos de distintas características accediendo simultáneamente a los mismos sistemas.

15 años después, las características y problemas subyacentes de los sistemas distribuídos siguen siendo más o menos los mismos. Cualquiera que haya puesto en producción sistemas distribuídos (qué sistema empresarial actual no lo es) ha sufrido la mayoría (si no todas) de estas realidades.

Definitivamente, lo que hay que tener claro es que no es posible proteger un sistema frente a todas estas eventualidades de forma indefinida ni es simplemente una cuestión de tecnología. Preservar a un sistema de las consecuencias de estos hechos ahora (es decir, para un momento concreto en el tiempo) es muy caro, así que se tiene que llegar a un compromiso entre el coste y riesgo que se quiere asumir. Incluso aún cuando se proteja de forma razonablemente un sistema, habremos de tener en cuenta que los sistemas crecen y evolucionan. Si no se presta atención a las cuestiones abarcadas por las falacias, llegará un momento en que la situación haya cambiado de forma sustancial y quede nuevamente expuesto.

Por tanto, estas falacias no solamente deben tenerse en cuenta en las etapas de diseño y construcción de un sistema, sino también (e incluso de forma especial) en la de mantenimiento, porque llegará un momento en que se mostrarán sus consecuencias... y no será tan tarde como imaginamos.


Referencias y más información:



lunes, 29 de noviembre de 2010

"Run As -> m2 Maven build" no funciona en Eclipse Helios

Puede que hayas llegado hasta aquí buscando alguna de las siguientes expresiones en un buscador:
  • No puedo ejecutar Maven en Eclipse Helios
  • No funciona maven en Eclipse Helios
  • Maven no hace nada en Eclipse Helios
  • Unable to start any of the Maven goals from Eclipse Helios
  • org.eclipse.core.runtime.CoreException: Local configuration cannot be nested in a directory
En efecto, el síntoma es que no se ejecuta "Maven build", "Maven package", "Maven clean" ni ningún otro goal del menú contextual "Run As" de m2e. Tras seleccionar la opción, no sucede nada ni se ve nada por consola. La ventana "Error Log" muestra: org.eclipse.core.runtime.CoreException: Local configuration cannot be nested in a directory.

Es un bug conocido de m2eclipse: https://issues.sonatype.org/browse/MNGECLIPSE-2191

La única solución que he encontrado hasta el momento es crear una configuración específica para cada proyecto y operación que quiero hacer. Estas configuraciones se pueden llamar desde el icono "Run As" de la barra de herramientas (el símbolo "play")


martes, 9 de noviembre de 2010

Firefox cumple seis años



Hoy, 9 de Noviembre, Firefox, el segundo navegador más usado, cumple seis años. Con una importante lista de premios a la espalda, es sin duda el navegador más personalizable que existe, el más seguro, y el menos "contaminado" por intereses comerciales, ya que detrás del mismo está la Fundación Mozilla, una fundación sin ánimo de lucro dedicada al software libre e innovación en internet.

El año que viene, veremos en su próxima versión (nº 4), importantes mejoras. Y además, ya está disponible (en versión beta) una versión para ciertos móviles.

Si no conoces la familia de productos Mozilla, te invito desde aquí a probar alguno de sus productos (todos gratuitos), especialmente Thunderbird con Lightning, la combinación de cliente de correo con calendario mejor que existe, con todas las ventajas de firefox: rapidez, seguridad, personalización (extremo a destacar especialmente)... y por supuesto, también gratis.

Firefox está disponible en más de 70 idiomas para Linux, Mac OS, y Windows.


Referencias y más información:

sábado, 16 de octubre de 2010

Control del nivel de aislamiento transaccional en JPA

La única ventaja de jugar con fuego es que aprende uno a no quemarse.

- Oscar Wilde (1854-1900)

Breve introducción al aislamiento

El aislamiento es una de las propiedades fundamentales ACID que definen las transacciones como tales en sistemas de gestión de bases de datos. El aislamiento define cómo y cuándo se ven los cambios realizados por una determinada operación por otras operaciones concurrentes.

El estándar ANSI/ISO SQL define cuatro niveles de aislamiento transaccional en función de tres hechos problemáticos que deben ser tenidos en cuenta entre transacciones concurrentes. Estos hechos no deseados son:

lectura "sucia"
Una transacción lee datos escritos por una transacción no confirmada [1]. Es decir, se leen datos temporales que no existirán finalmente porque la transacción que los creó se canceló finalmente tras la lectura.
lectura no repetible
Una transacción vuelve a leer datos que previamente había leído y encuentra que han sido modificados por una transacción confirmada.
lectura "fantasma"
Una transacción vuelve a ejecutar una consulta, devolviendo un conjunto de filas que satisfacen una condición de búsqueda y encuentra que otras filas que satisfacen la condición han sido insertadas o borradas por otra transacción cursada. La inconsistencia ocurre cuando una segunda transacción accede repetidas veces a una fila y lee datos diferentes cada vez.

Como comentaba, los niveles de aislamiento se definen en función de los efectos no deseados que evita. Así, el estándar ANSI/SQL define los siguientes cuatro niveles de aislamiento, de menor aislamiento a mayor:


lectura sucia
(dirty reads)
lectura no repetible / doble actualización
(non-repeatable reads / lost-update)
lectura fantasma
(phantom reads)
lectura no confirmada
READ_UNCOMMITTED
Se produce efecto
Se produce efecto
Se produce efecto
lectura confirmada
READ_COMMITTED
No se produce efecto
Se produce efecto
Se produce efecto
Iectura repetible
REPEATABLE_READ
No se produce efecto
No se produce efecto
Se produce efecto
secuenciable
SERIALIZABLE
No se produce efecto
No se produce efecto
No se produce efecto

Las transacciones tienen aislamiento cuando no interfieren entre sí, especialmente aquellas que aún no han concluído y están incompletas. El nivel de aislamiento es inversamente proporcional al rendimiento final en la medida en que que cuanto mayor es el aislamiento mayores son los recursos del sistema utilizados para garantizarlo. Esto se hace patente con un alto grado de concurrencia: a un nivel de aislamiento mayor, menor rendimiento.

La mayoría de las bases de datos usan un el nivel de aislamiento READ_COMMITED por defecto. Para accesos clásicos a la base de datos usando un patrón DAO y gestionando las conexiones directamente (sin usar JPA) esto es prácticamente lo único que necesitamos, ya que podemos seleccionar un nivel de aislamiento mayor en caso que lo necesitemos en la conexión usando setTransactionIsolation().


Con JPA las cosas son bastante diferentes

Hay que tener en cuenta que las implementaciones de JPA incluyen una caché de objetos que introduce elementos nuevos y desconcertantes frente las aplicaciones clásicas.

Otras aplicaciones acceden a los datos
Nuestra aplicación puede convivir con otras aplicaciones JPA que no usen la misma Unidad o Contexto de Persistencia (otro módulo, otro servidor) o que accedan a los datos directamente sin un framework JPA de por medio. Esto causará lecturas no repetibles, es decir, que ambas aplicaciones sobreescriban los mismos datos simultáneamente. En definitiva, el framework no realiza un refresco automático de un objeto antes de realizar un merge() (si lo hiciese, sería costoso ya que ejecutaría una sentencia SELECT anterior a cualquier otra). El tema del "refresco" de la caché es un tema aparte que merecerá un articulo aparte, en su momento.

Objetos caducados
Incluso aunque todas las aplicaciones usen el mismo contexto de persistencia y la misma caché de objetos, es frecuente que dos threads modifiquen el mismo objeto (incluso aunque sean propiedades diferentes) y realicen una transacción simultánea sobreescribiendo los cambios de otra, con lo que podemos tener que "se pierden" cambios de una propiedad. Por ejemplo:
  1. La transacción A lee la fila x.
  2. La transacción B lee la misma fila x.
  3. La transacción A escribe la fila x.
  4. La transacción B escribe la fila x (y sobreescribe los cambios realizados por A).
  5. Ambos confirman la transacción con éxito.
Este efecto se conoce típicamente como actualización perdida (Lost update). Con un nivel de aislamiento SERIALIZABLE esto no ocurriría, ya que la transacción B se quedaría bloqueada esperando hasta que la transacción A realizara la confirmación (commit) o no esperaría y simplemente fallaría (dependiendo de si se emplea un NO_WAIT en el tipo de lock). Sin embargo, en una aplicación web típica, esto seguiría generando un conflicto aún con un nivel SERIALIZABLE, ya que una aplicación web leería (y presentaría) primero los datos en una transacción y los actualizaría en otra).

Otro casos parecidos a éste y con consecuencias similares son:
  • un thread borra un objeto (delete()) y otro realiza un persist() sobre él. En ambos casos tendremos información inconsistente: o no se ha borrado, y tenemos dos, o no se ha grabado y no tenemos ninguno.
  • un objeto tiene relaciones con otros objetos hijos. Las modificaciones en las listas de sus hijos relacionados puede causar igualmente información inconsistente con respecto a los hijos.

Mecanismos de control de concurrencia
Para evitar estos problemas existen los mecanismos de control de concurrencia, que se encargan de mantener el aislamiento transaccional. Existen múltiples métodos de control de concurrencia que se pueden agrupar en tres categorías:
  • Optimistic. No realiza bloqueos, cancelando la confirmación y revertiendo los cambios (rollback) en caso de que se detecte un conflicto con otras transacciones. Como su propio nombre indica, asume que las transacciones pueden avanzar y realiza las comprobaciones de modificación al final, justo antes de realizar la confirmación de la transacción, asegurándose que los datos no han cambiado desde que se leyeron. Previene "lost updates".
  • Pessimistic. Se adquieren bloqueos sobre los objetos que se van a editar (típicamente las implementaciones lo realizan meidante sentencias SELECT ... FOR UPDATE). Este enfoque equivale a un nivel de aislamiento SERIALIZABLE.
  • Semi-optimistic. Es una mezcla de ambos realizando bloqueos sólo en determinadas situaciones.

Mecanismos de control de concurrencia en JPA

Por defecto, las implementaciones (persistence provider) de JPA asumen que la aplicación es responsable de la consistencia de datos y, por tanto, no realizan ningún comportamiento por defecto relativo a bloqueos. Como he comentado, trabajando directamente con la conexión de base de datos, podemos establecer un nivel de aislamiento y controlar la concurrencia, pero en JPA no manejamos directamente la conexión, sino que trabajamos con un gestor de entidades (EntityManager). Entonces, ¿cómo hacemos para gestionar la concurrencia si no podemos establecer un nivel de aislamiento?. Y aunque pudiéramos, ¿como resolvemos los problemas añadidos inherentes a JPA como los objetos caducados?. Vamos a ello.

Optimistic locking
JPA soporta optimistic locking mediante un campo versionado de bloqueo, definido por la anotación @Version. Dicho campo se actualiza automáticamente por la implementación JPA en cada actualización y debe ser conservado tal cual por la aplicación. En el momento de la realización del merge(), si se detecta un bloqueo o cambio, se lanza una excepción OptimisticLockException.
@Entity
public class Debt {
    @Id
    private long id;
    @Version
    private long version;
    //...
}

Bloqueos específicos de lectura y escritura
Algunas veces es deseable bloquear algo que no vas a cambiar. Normalmente se hace cuando vas a realizar un cambio sobre un objeto que se base en el estado de otro, y deseas asegurar que éste último no cambia mientras dura la transacción. JPA soporta bloqueos de lectura y escritura a través del método EntityManager.lock(entity, lockMode). El argumento lockMode puede ser READ o WRITE.

Si una transacción llama a lock(entity,LockModeType.READ) sobre un objeto versionado nos aseguraremos de que no se realizará ninguna lectura sucia ni lectura no repetible. Es decir, se asegura de que el objeto no ha cambiado antes de hacer el commit. En caso contrario, se lanzará una OptimisticLockException. Por ejemplo, en un método evaluamos en una condición un atributo de un
objeto y, en función del valor, realizamos una modificación de otro objeto.
    ut.begin();
    Debt d = em.find(Debt.class,5);
    em.lock(d,LockModeType.READ);
    if ( d.getAmount() < 10 ) 
        throw new MinAmountExceedException();
    ut.commit();

Si una transacción llama a lock(entity,LockModeType.WRITE) nos aseguraremos de que no se realizará ninguna lectura sucia ni lectura no repetible, ni otro objeto está realizando un lock. En caso contrario, se lanzará una OptimisticLockException. El bloqueo WRITE puede usarse también para proporcionar bloqueos a nivel de objeto y sus objetos dependientes, es decir, bloquear (aunque deberíamos decir "detectar") cambios en relaciones, de forma que un cambio en una lista de objetos hijos fuerce el incremento del número de versión del objeto padre.


En definitiva, el bloqueo READ comprueba el optimistic version field (campo de versionado), y el bloqueo WRITE lo comprueba y lo incrementa. Este tipo de bloqueos es justo lo que se obtiene con un nivel de aislamiento serializable pero de forma optimista, es decir, sin riesgos de deadlock o bloqueos abiertos, ya que estamos hablando de comprobaciones" no de bloqueos efectivos como tales.


Pessimistic locking
Pessimistic locking significa adquirir un bloqueo sobre el objeto antes de comenzar a editarlo y equivale a un nivel de aislamiento SERIALIZABLE. Es realmente bloquear, no es una simple comprobación como en el bloqueo optimista. Se implementa típicamente con una sentencia SELECT ... FOR UPDATE. El bloqueo pesimista no está incluido en JPA 1.0, aunque algunas implementaciones sí lo hacen. Si usamos JPA 1.0 (por ejemplo usando la implementación por defecto de Glassfish 2.x), las alternativas para realizar este bloqueo serían las siguientes:
Por ejemplo:
@Entity
@Table(name="mailing_package")
@NamedQueries( {
    @NamedQuery(name = "MailingPackage.findByIdLocked",
        query = "SELECT s FROM MailingPackage s WHERE s.id = :id",
        hints={ @QueryHint(name = "toplink.pessimistic-lock", value = "LockNoWait")} })
public class MailingPackage implements Serializable {
...
}

El bloqueo pesimista hay que manejarlo con cuidado porque puede causar problemas de concurrencia, rendimiento o bloqueos de la aplicación por deadlocks. Típicamente no es deseable para aplicaciones web interactivas, ya que requiere mantener la transacción (y por tanto la conexión) activa durante la edición. El uso típico es cuando se quiere que la edición tendrá éxito en un momento que sabemos que la transacción durará lo menos posible.


Bloqueos en JPA 2.0
JPA 2.0 añade soporte específico para bloqueo pesimista además de otras opciones de bloqueo en el propio API. Un bloqueo se puede adquirir usando adquiere usando el método EntityManager.lock(entity, lockMode), pasando un argumento LockModeType a los nuevos métodos sobrecargados find() y refresh(), o estableciendo un lockMode en una Query ( setLockMode() ) o NamedQuery (lockMode).

JPA 2.0 amplia/redefine los modos de bloqueo de JPA 1.0 en el enum LockModeType:
  • OPTIMISTIC: Es el READ de JPA 1.0
  • OPTIMISTIC_FORCE_INCREMENT: Es el WRITE de JPA 1.0
  • PESSIMISTIC_READ: Bloquea y evita que otra transacción adquiera un bloqueo PESSIMISTIC_WRITE.
  • PESSIMISTIC_WRITE: Bloquea y evita que otra transacción adquiera bloqueos PESSIMISTIC_READ o PESSIMISTIC_WRITE.
  • PESSIMISTIC_FORCE_INCREMENT: es una suma de PESSIMISTIC_WRITE y OPTIMISTIC_FORCE_INCREMENT.
  • NONE: No hay bloqueo ni comprobación. Equivalente a omitir cualquier lockMode.
Adicionalmente, JPA 2.0 añade dos hits estándar que pueden pasarse a qualquier Query o NamedQuery y a qualquier operación find(), lock() o refresh():
  • "javax.persistence.lock.timeout": Número de milisegundos a esperar la liberación del bloqueo antes de lanzar una PessimisticLockException.
  • "javax.persistence.lock.scope": Los alcances válidos se definen en PessimisticLockScope (NORMAL or EXTENDED).  EXTENDED bloqueará adicionalmente las tablas relacionadas.

Conclusiones

Con el nivel por defecto de la base de datos en READ_COMMITED y usando un bloqueo optimista para detectar lost-updates, sólo necesitaríamos realizar un bloqueo pesimista en muy pocos casos. No obstante, estos casos existen: casos como un objeto que deba tener una numeración "sin huecos" (como el clásico ejemplo de los números de factura) o un repartidor de objetos que no deba dar el mismo objeto a dos threads para su proceso, podría requierir un bloqueo pesimista o secuenciable que impida de dos threads lean simultáneamente el mismo valor y lo incrementen.

Recomiendo echar un vistazo a las referencias al final del artículo para profundizar más en el tema. Aprovecho la ocasión para felicitar aquí a los autores de "Java Persistence", de en.wikibooks.org, que han hecho un trabajo impecable el cual me ha sido de enorme ayuda para comprender el complejo mundo de JPA.


NOTAS:
[1] Creo que la traducción de "commited" como "cursado" o "confirmado" es más correcta en este contexto.


Referencias y más información:

jueves, 9 de septiembre de 2010

Eclipse Helios e integración con SVN, Maven y Glassfish

Desde el año 2006, la fundación Eclipse produce a finales de Junio una versión coordinada simultánea de decenas de proyectos de código abierto consolidados en una herramienta de desarrollo conocida comúnmente como Eclipse IDE, de la que se ponen disponibles 12 empaquetados distintos según el propósito de desarrollo, plataforma tecnológica y necesidades del desarrollador. Desde el 23 de Junio de este año está disponible la versión 3.6 denominada Eclipse Helios.

El modo de distribución de Eclipse es análogo al de una distribución de Linux como Ubuntu y, por tanto, con la misma potencia, comodidad y efectividad. Los distintos paquetes son, en definitiva, distintas combinaciones de proyectos con sus dependencias debidamente resueltas contra los repositorios de Eclipse. Las actualizaciones, en línea, también son similares a las que se realizan con Ubuntu, con lo que la integridad de dependencias está asegurada. En definitiva, una buena idea extendida a las herramientas de desarrollo.


La comunidad de Eclipse tiene cientos de plugins, tanto de código abierto como comerciales, no todos hospedados eclipse.org, que pueden ser de interés. El sistema de repositorios de Eclipse, si bien resuelve correctamente dependencias, requiere que añadamos manualmente las url's de las fuentes de software que queremos instalar. Una de las novedades de Eclipse Helios se acerca aún más a la analogía comentada añadiendo al sistema de repositorios de Eclipse una herramienta de alto nivel llamada Eclipse Marketplace Client (MPC). MPC funciona como un almacén de aplicaciones y plugins (app store) centralizado permitiendo la descarga e instalación de forma cómoda, automática e integrada en nuestro Eclipse.




Para trabajar con un proyecto JEE me gusta que mi Eclipse tenga los plugins de integración con Subversion (SVN), Maven y Glassfish (o el servidor de aplicaciones con el que vaya a trabajar). Por alguna razón que desconozco, Helios aún no trae "de serie" la integración con Maven y SVN. Es posible que sea por mantener escrupulosamente la libertad del desarrollador ya que existen varios plugins disponibles, de los cuales, los más conocidos son:
  • Maven
    • m2eclipse (m2e), el "oficial" de los chicos de Maven (Sonatype) y que, por cierto, se está trasladando de codehaus.org a eclipse.org
    • Eclipse IAM, antiguo q4e de los chicos de Apache
  • SVN
    • subclipse, el "oficial" de los chicos de SVN
    • subversion, el "oficial" de los chicos de Eclipse

En mi caso, yo instalo "Maven Integration for Eclipse" (m2eclipse), "Subversive - SVN Team provider" para SVN y "Glassfish Java EE Application Server Plugin for Eclipse".




Referencias:

lunes, 5 de julio de 2010

Actualizar el firmware de la BIOS vía USB con linux

Denme un punto de apoyo y moveré el mundo.

- Arquímedes de Siracusa. (c. 287 a. C. – c. 212 a. C.)


Recientemente tuve que actualizar el firmware de la BIOS de mi placa base y me encontré con la desagradable sorpresa de que las opciones del fabricante eran exclusivamente para Windows y DOS. Para los que usamos linux esto es un grave inconveniente, porque no tenemos ni lo uno ni lo otro, ni mucho menos ganas de adquirir una licencia sólo para esa simpleza. Incluso en el caso que pudiese adquirir una licencia, está el problema de no disponer de disquetera, de la cual carecen todos los equipos recientes.

Afortunadamente, el disgusto no me duró mucho porque el mundo del software libre ofrece muchas y variadas soluciones para esta tarea. Durante la búsqueda de soluciones para este problema me reencontré con algunos viejos proyectos que siguen felizmente muy activos y están actualmente en un estado muy interesante, como FreeDOS (un sistema operativo libre compatible con MS-DOS) y ReactOS (el renacimiento de aquel digno pero malogrado Freewin95)... ufff... uno ya va teniendo una edad...

De todas las soluciones posibles, traigo a este artículo la que más me gustó y me pareció más sencilla y sólida: UNetbootin.


UNetbootin te permite crear unidades de arranque USB de forma automática y transparente de numerosas distribuciones de Linux, utilidades diversas (reparación, recuperación, bootloaders, etc) y FreeDOS.

Adicionalmente, es capaz de crear un disco de arranque a partir de cualquier imagen ISO (o disquete) de arranque, kernel o ficheros intrd, que queramos, con lo que las posibilidades se multiplican.

El software están disponible también, a su vez, en los repositorios y/o paquetes de para las distribuciones de Linux más conocidas, y también para Windows. Por supuesto, como software libre que es, está disponible el código para cualquier otro caso raro no contemplado.

En el caso que nos ocupa, en apenas unos minutos pude descargar del repositorio el software (sudo apt-get install unetbootin) crear una unidad de arranque en un lápiz USB con FreeDOS y ejecutar la utilidad DOS para actualizar la flash de la BIOS de mi sistema. Todo con software libre (¡y gratuito!).


Referencias:

jueves, 24 de junio de 2010

XML con PostgreSQL

En el artículo Alternativas EAV con XML expliqué cómo se podía implementar una mejora del modelo Entity Attribute Value (Entidad-Atributo-Valor) usando XML. Este artículo es, en alguna medida, una continuación de aquél, cubriendo ciertos aspectos importantes sobre la consulta a éstos campos o cualquier otro campo que contenga xml. El uso de las características de este artículo requiere que la instalación de postgresql se haya realizado con el soporte xml (configure --with-libxml).

Serialización/deserialización XML de campos varchar
Hay ocasiones en que necesitamos que los campos que contienen XML sean de tipo caracter y no de tipo xml nativo. Una razón para hacer eso, por ejemplo, es que estemos usando un ORM. En algunos casos, pongamos por ejemplo PostgreSQL con Toplink Essentials (incluído de serie en Glassfish 2.1), no hay forma (al menos yo no la he encontrado) de que el ORM haga mapping de campos de tipo xml. Para estos casos, en primer lugar, debemos producir un valor de tipo xml a partir de datos carácter, para lo que podemos usar la función xmlparse o realizar un type cast a xml usando la sintaxis tradicional de PostgreSQL expression::type o bien usando la sintaxis SQL-92 estándar CAST ( expression AS type ), así:

SELECT XMLPARSE( DOCUMENT campo)
FROM tabla
WHERE campo  is not null
<=>
SELECT cast(campo as xml)
FROM tabla
WHERE campo is not null
<=>
SELECT campo::xml
FROM tabla
WHERE campo is not null



Consultas: la función xpath

Para procesar valores de tipo xml, PostgreSQL ofrece la función xpath, que evalúa expresiones XPath 1.0.

xpath(xpath_expr, xml_value[, nsarray])

La función xpath evalúa la expresión XPath xpath_expr contra el valor XML xml_value (debe ser un documento XML bien formado), devolviendo un array de valores XML correspondiente al conjunto de nodos producidos por la expresión XPath. El tercer argumento, opcional, es el array bidimensional de espacios de nombress (nombre espacio de nombres,URI espacio de nombres) que use el documento XML xml_value.


Por ejemplo, dado un campo campo de la tabla tabla, de tipo varchar(2048), podríamos consultar el contenido así (a partir de este momento usaremos la sintaxis del último ejemplo, la tradicional de PostgreSQL, por ser la más sencilla):

Consulta
Resultado
SELECT campo::xml
FROM tabla
where campo is not null
campo
----------------------------------------------------------
<xmlData><data name="incidencia">
<data  value="tiempo"  name="motivo"/></data></xmlData>
<xmlData><data name="incidencia">
<data value="hardware"  name="motivo"/></data></xmlData>
<xmlData><data name="incidencia">
<data value="hardware"  name="motivo"/></data></xmlData>
<xmlData><data name="cantidad" value="2"></xmlData>
<xmlData><data name="cantidad" value="3"></xmlData> 



Es importante recordar que la función xpath devuelve un array de valores XML. Por ejemplo, si deseamos consultar sólo el contenido de aquellos valores de elementos data cuyo name es "motivo", por eso la siguiente consulta nos devuelve 4 filas. Es decir, de las cuatro filas en las que campo tiene valores, sólo dos de ellas tiene un elemento data con name igual a 'motivo', pero como xpath devuelve un array de valores, en las los dos últimas filas se devuelve un array vacio.


Consulta
Resultado
SELECT  xpath('//data[@name=''motivo'']/@value',campo::xml) as motivos
FROM  tabla
where campo is not null
motivos
----------
{tiempo} 
{hardware}
{}
{}


Para evitar lo anterior, podemos hacer:


ConsultaResultado
SELECT  xpath('//data[@name=''motivo'']/@value',campo::xml) as motivos
FROM tabla
where campo is not null
and  array_upper(xpath('//data[@name=''motivo'']',campo::xml),1) is not null
motivos
------------
{tiempo}
{hardware}



La consulta anterior elimina aquellas filas con array vacío. No obstante, xpath() nos sigue devolviendo un array que tendremos que procesar posteriormente. Para que nos devuelva valores de tipo xml (u no un array) tendremos que tratar la respuesta de xpath como array y pedir el primer elemento del mismo. Así:



ConsultaResultado

SELECT  (xpath('//data[@name=''motivo'']/@value',campo::xml))[1] as motivos
FROM tabla
where campo is not null
and  array_upper(xpath('//data[@name=''motivo'']',campo::xml),1) is not null
motivos
-----------
tiempo
hardware



Obviamente, podemos usar la función xpath no sólo para seleccionar valores (uso en la select list de la sentencia SELECT) sino también en la cláusula WHERE, para filtrar filas. En este último caso, tendremos que realizar una conversión de tipo para poder realizar ciertas comparaciones (comparación de valores enteros, de fechas, etc...). La conversión a realizar debe ser un poco especial, ya que deberemos convertir de xml a varchar y de éste al tipo deseado. Por ejemplo:

SELECT (xpath('//data[@name=''cantidad'']/@value',campo::xml))[1]::varchar::int4
FROM step
where campo is not null
and array_upper(xpath('//data[@name=''cantidad'']',campo::xml),1) is not null
and (xpath('//data[@name=''cantidad'']/@value',campo::xml))[1]::varchar::int4 > 2

Con lo que conseguiríamos todas aquellas filas con xml que tengan un elemento data con nombre "cantidad" cuyo valor sea superior a 2.


Con esto, podemos usar un modelo más flexible (especialmente para valores de poca densidad) al modelo EAV y con consultas más asequibles.

Referencias:

miércoles, 19 de mayo de 2010

WSTX-SERVICE-5002: A JTA Transaction MUST NOT exist entering WS-TX Service Pipe procesing for binding... SOLUCIONADO

JAX-WS representó una revolución en la implementación de SOAP Web Services en JEE. Su aparición en JEE 5 nos permitió publicar como Web Service un Stateless Session EJB automáticamente, de forma declarativa, añadiendo simplemente la anotación @WebService. Sin embargo, bajo determinadas condiciones, nuestro cliente se puede encontrar con un error que, a priori, nos puede resultar desconcertante:

WSTX-SERVICE-5002: A JTA Transaction MUST NOT exist entering WS-TX Service Pipe procesing for binding '{http://jdialer.sgi.gesif/}dataproviderPortBinding' and operation 'getContacts'. JTA Transaction is  J2EETransaction: txId=51 nonXAResource=null jtsTx=com.sun.jts.jta.TransactionImpl@d419b987 localTxStatus=0 syncs=[]....


Tras este error suelen producirse otros dos igualmente desconcertantes: "HTTP transport error: java.net.UnknownHostException: host_cliente" o el clásico SSL Handshake "HTTP transport error: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target". Es decir, es como si nuestro servidor estuviese intentando contactar con nuestro cliente por HTTPS. ¿Por qué lo hace?

Una pista: las condiciones en las que se da este error es si el cliente es un EJB. Sólamente en ese caso. Si es un servlet, o una aplicación standalone, funciona perfectamente. ¿Esto te da una idea o aún te confunde más?

La explicación es, en realidad, muy sencilla: los EJB's tienen el atributo de transacción establecido por defecto a REQUIRED (@TransactionAttribute(TransactionAttributeType.REQUIRED)). El código cliente del Web Service lo tiene en cuenta y añade un contexto transaccional al mensaje SOAP. Si EJB "servidor" ha declarado que no necesita transacciones (@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)), ya tenemos el problema servido. La solución en estos casos es también sencilla, debemos indicar a nuestro cliente que no use un contexto transaccional en la petición, anotándolo con @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED), y así el servidor no usará el coordinador WSTX (Web Service Transactions).

miércoles, 14 de abril de 2010

La galaxia en un campo de fútbol

Cuando veas un gigante, examina antes la posición del sol; no vaya a ser la sombra de un pigmeo.

- Novalis (1772-1801) Friedrich von Hardenberg. Poeta y filósofo alemán.


En el artículo Magnitudes astronómicas describía mi fascinación por los enormes tamaños de algunos cuerpos astronómicos. La mejor forma de "entender" realmente cómo eran de grandes era, obviamente, ubicándolos en nuestro mundo cotidiano, es decir, comparándolos con objetos conocidos.
Como prometí en dicho artículo, hoy voy a comentar el libro "La Galaxia en un campo de fútbol".

En mi artículo me limité al tamaño de algunos cuerpos de forma singular. "La Galaxia en un campo de fútbol", en cambio, es una exposición sistemática, pero al mismo tiempo muy amena, en la que se nos plantea un método que nos permite imaginar las distancias astronómicas para comprender (e imaginar también, en definitiva) el universo. Desde nuestro "entorno" más cercano, la tierra y sus satélites (artificiales y naturales), donde las distancias se miden en miles de Km, hasta abarcar la visión global del Universo conocido, donde las distancias se miden en millones de años luz, la obra desarrolla el método de forma muy ilustrativa y con ejemplos, de forma que nos permite por primera vez "imaginar" realmente dichas distancias. Así, los que nos hemos leído el texto, podemos entender realmente noticias como las del pasado 8 de Abril sobre un asteroide que pasó rozando la tierra, comprendiendo realmente las distancias que se indican y realizando cada uno nuestra propia valoración sobre lo "cerca" o "lejos" que está algo según el sistema de referencia y dependiendo con qué distancias comparemos (desde luego, un objeto como el 2009 VA del pasado Noviembre sí que pasó "cerca"... cualquier día de éstos se llevan un satélite geoestacionario por delante).

El libro está escrito pensando en lectores interesados por el tema, pero no presupone conocimiento alguno sobre astronomía, de forma que un lector curioso y lego en la materia podrá disfrutar tanto o más que un aficionado. De hecho, el autor, en un esfuerzo (supongo) por mantener un lenguaje cercano y ameno, dota el libro de un estilo de redacción en la que entabla un diálogo con el lector, consiguiendo un resultado entretenido y accesible aunque quizá de forma desmedida, resultando al final (en mi modesta opinión y por poner alguna pega) un poco pueril e ingenuo (eso de pedir al lector que haga algo y luego felicitarlo por hacerlo me parece un poco excesivo).

Por lo demás, el ejemplar está editado en un tamaño muy cómodo e impreso en un papel excelente, permitiéndonos disfrutar de las maravillosas fotografías astronómicas que incluye.

En definitiva, una obra muy atractiva que volveré a releer y disfrutar para asimilar bien "el método" y continuar "imaginando" el universo. Os la recomiendo.


Referencias:

jueves, 25 de marzo de 2010

Generación de código JAXB con Maven

Si tu intención es describir la verdad, hazlo con sencillez y la elegancia déjasela al sastre.
- Albert Einstein.

Al hilo de lo que comentaba en el artículo "Desarrollo en equipo con SVN, Maven y Nexus", una de las maravillas de usar Maven es que te facilita la reproducibilidad, por ejemplo, de la gestión de la configuración de un proyecto. El caso que voy a exponer es un estupendo ejemplo: la generación de código JAXB a partir de esquemas XML (XSD).

La generación de código JAXB se ha venido haciendo típicamente de dos formas: a través de una herramienta o utilidad (wizard, plugin, etc...) de nuestro IDE, o "manualmente" usando la tarea xjc de ant, o el compilador xjc por línea de comando directamente. Personalmente, nunca me ha gustado usar las herramientas automáticas de los IDE, porque ocultan la configuración del proyecto: los settings que se configuran en un wizard del IDE se acaban perdiendo porque no se suben al repositorio de código o si se hace, atas el proyecto a una herramienta que puede que no uses (tú u otro compañero a quien le toque modificarlo) varios meses después cuando te encuentras con el mantenimiento de un proyecto cuya configuración no es reproducible. Además, esa tarea suele ser repetitiva y necesita ser ejecutada a menudo, especialmente en las fases iniciales donde se va ajustando nuestro esquema XML a los tipos de dato que vamos necesitando, de modo que acabo haciendo "a mano" una tarea ant que realice la generación o un shell script que realice la llamada al compilador xjc con los parámetros que quiero.

Afortunadamente, podemos hacer que Maven realice esta tarea automáticamente como parte de sus labores de construcción, y como tenemos nuestro pom.xml subido a svn, todas nuestras preferencias de generación permanecen autocontenidas en el proyecto: simple, sencillo y sin ataduras a ningún IDE.

Iba a poner aquí los trozos necesarios a incluir en el pom.xml extraído de uno de los módulos del proyecto en el que estoy trabajando pero, la verdad, sería redundante porque está perfectamente explicado en el sitio del plugin JAXB XJC de Maven.

En mi caso, que uso Eclipse con m2eclipse (plugin de maven para eclipse), la integración con Maven es tal, que basta con realizar una modificación el XSD y salvarlo para que se regenere y recompile la clase automáticamente y tenga disponibles los nuevos métodos en mis clases "cliente" de forma instantánea (m2eclipse ejecuta el "generate" de Maven integrado con el propio build de Eclipse).

Otra razón más para continuar recomendando usar Maven.

Referencias:

domingo, 7 de marzo de 2010

Balteus cumple un año

“Yo…he visto cosas que vosotros no creeríais. Naves de guerra ardiendo más allá de Orión. He visto rayos-c resplandecer en la oscuridad, cerca de la puerta de Tanhäuser. Todos esos…momentos se perderán…en el tiempo. Como…lágrimas…en la lluvia. Es hora…de morir”.

--Roy Batty, Blade Runner.

Ya ha pasado un año desde mi primer artículo. Una primera entrada impetuosa que escribí sin presentación, casi por rabia, tras perder demasiado tiempo en un error absurdo, de ésos que te vuelven loco, y de los que sólo te sirven para aprender que debes cuestionarlo todo y no dar nada por sentado. Fue en ese estado de rabia contenida y aliviada, tras solucionar el error, cuando decidí que debía compartir estas experiencias con otros desarrolladores, tal y como hacen miles de compañeros alrededor del mundo, de cuyos trabajos y generosidad me he ido aprovechando durante años, ahorrándome muchas horas y disgustos. Tras ése primer post, escribí realmente la presentación del blog con mis motivos y objetivos.

He querido comenzar este post con la que es, probablemente, la cita más conocida de todos los locos entusiastas del cine de ciencia ficción... Parece una entrada melancólica, pero nada de eso en absoluto: simplemente es un homenaje a Ridley Scott y a la película. Yo creo que no hay desarrollador que no haya dicho o pensado algo así tras una puesta en producción... ¿eh? ;-)

1 año. 25 Entradas. 2 entradas al mes, de media. Menos de lo que me gustaría... pero no encuentro tiempo para mucho más. "La falacia de la Ingeniería del Software" y los artículos de la serie "Banco de experiencias" son probablemente las entradas de las que me siento más satisfecho (aunque, curiosamente, no son las que más interés despiertan). De los datos y números que aporta Google Analytics, destacaría dos cosas:
  • La gente busca soluciones. Las entradas más consultadas son aquellas en las que comento cómo he solucionado un error o problema. Lo cual es lógico. En mi caso también ha sido así. Muchos de los blogs en los que he aterrizado ha sido vía google, buscando una determinada solución. En definitiva, cuando tenemos un problema, buscamos si a otra persona le ha pasado lo mismo antes de perder más tiempo. Como digo, constato una evidencia que ya suponía.
  • Realmente el blog tiene visibilidad en todas partes del mundo. Internet hace que todo el mundo sean un montón de ordenadores conectados sin importar localización, idioma o frontera. Parece evidente. Es evidente. Sin embargo, cuando lo confirmas con datos concretos da cierto vértigo. Asumes las lógicas visitas de España y países de habla hispana (al fin y al cabo escribo en español)... pero llaman la atención visitas de Estados Unidos, Alemania, Suiza, Rusia, Brasil, Polonia, India, Finlandia, Corea... ¿Hispanohablantes por el mundo? ¿O simplemente hay gente que busca su respuesta esté en el idioma que esté? (yo lo hago... quizá los angloparlantes, germanoparlantes, etc... también).
En fin, son un par de obviedades con las que todo el mundo cuenta... pero que nunca dejan de sorprender. Al fin y al cabo tenemos una dimensión local y finita... Que lo que escribes pueda ser de interés para alguien tan lejano, impresiona, la verdad.

En todo caso tendré en cuenta estas reflexiones para mis próximas entradas. Es posible que los localismos comentados en "Magnitudes astronómicas" no sean tan claros para gente que no conoce Madrid. Por otro lado, es difícil no hacer referencias al mundo que te rodea. Con respecto a la temática, mi trabajo diario suele darme material de sobra para seguir compartiendo "soluciones" y "experiencias". Así que seguiré en ello.

Gracias a los que visitáis el blog, seáis de donde seáis. Un afectuoso saludo.

lunes, 22 de febrero de 2010

Desarrollo en equipo con SVN, Maven y Nexus (parte II)

Banco de experiencias (V)

En la primera parte de este artículo, enumeraba los problemas de coordinación a los que se enfrenta un equipo de desarrollo diariamente y cómo la utilización de Maven los soluciona de un plumazo por el simple hecho de utilizarlo. Hay un problema sin embargo, inherente al desarrollo en equipo, para el cual se necesita una herramienta más: un gestor de repositorios.

Imaginemos el siguiente escenario de proyecto: un equipo está desarrollando una aplicación empresarial (ear) formada por un par de módulos web, otro par de módulos ejb (ejb-jar), un conector JCA (rar) y tres módulos de librerías comunes (jar).

En un proyecto de éstas características (proyecto con varios módulos) cada desarrollador trabaja en uno o varios módulos (en función de la funcionalidad, de su perfil, habilidades o experiencia...), pero no suele participar en todos... Al menos, eso es lo habitual. Sin embargo necesita tener las actualizaciones y los progresos de todos (o la mayoría) de los módulos, debido a las dependencias entre ellos. Estas dependencias inter-proyecto o inter-módulo son las que denominé como dependencias internas en la primera parte de este artículo. Pero ¿ćomo estar actualizados y poder tener las nuevas funcionalidades y servicios que han desarrollado nuestros compañeros para poderlos usar en los módulos que estamos desarrollando? Típicamente esto se hace de dos formas:
  1. Todos los desarrolladores tienen todos los proyectos creados en su IDE y vinculados con SVN o, al menos, los proyectos en los que está trabajando, los proyectos dependientes, y los dependientes de los dependientes (dependencias transitivas), y así sucesivamente... es decir, típicamente todos. Esto es lógicamente un engorro, porque cada vez que alguien realice una refactorización que suponga la creación de un nuevo proyecto, afectará a todo el equipo de desarrollo. Todos los cambios impactan a todos (cambios en la configuración, dependencias, nuevos proyectos, etc...), favoreciendo, además, la incidencia de errores dada la exposición de todos los fuentes a todo el equipo.
  2. Los desarrolladores que trabajan en proyectos que son requeridos por el resto "publican" sus artefactos en SVN o un repositorio común en red. Esta segunda opción introduce complejidad de configuración y coordinación en el equipo y scripts adicionales que realicen esas tareas, ya que hay que "avisar" de cuando hay que actualizar las dependencias... en todo caso: la gestión de las dependencias (en este caso internas) se manejan manualmente vía scripts (típicamente de ant).

Software de gestión de repositorios Maven

El software para de gestión de repositorios Maven sirve precísamente para eso: para crear y gestionar nuestros propios repositorios de Maven. De esta forma tendremos la gestión de dependencias solucionada:
  • las dependencias externas, a través del mismo Maven, usando el repositorio Central. También podemos crear nuestros propios repositorios proxies de otros, reduciendo el tráfico de red.
  • las dependencias internas (o inter-proyecto) con nuestro repositorio.
Veamos el siguiente ejemplo: tenemos un equipo de tres desarrolladores que está desarrollando una aplicación que tiene un módulo JAR, que a su vez es usado por un módulo EJB y otro módulo WAR que usa (necesita) los dos anteriores.
  • El desarrollador A participa en el desarrollo del módulo EJB, y es el único que desarrolla el módulo JAR. Este desarrollador no tiene que resolver dependencias internas, digamos que es un "productor" y debe "publicar" su trabajo para los demás.
  • El desarrollador B sólo trabaja en el módulo WAR: por tanto debe disponer de los otros proyectos. Sería el caso del "consumidor" exclusivo.
  • El desarrollador C trabaja en los módulos WAR y EJB: es decir, es consumidor y productor a la vez. Debe publicar su trabajo, pero también requiere del trabajo del desarrollador A.



En el caso anterior, usando un repositorio remoto con un software de gestión de repositorios, Maven realizará todos los trabajos de sincronización de forma transparente, realizando la publicación de artefactos al repositorio (mvn deploy) para los desarrolladores A y C, y la actualización automática para todos. Lo único que hay que hacer es especificarle la URL del repositorio en los pom.xml de los proyectos, simplificando enormemente la coordinación en proyectos reales típicos (más grandes, complejos y con más desarrolladores).

El software repositorio que yo conozco es Nexus, de la compañía que creó Maven (Sonatype), y la verdad, estoy muy satisfecho con su funcionamiento. No obstante, hay otros también bastante usados como Apache Archiva, o Artifactory. En general, todos parecen cumplir correctamente su misión principal y tienen una instalación sencilla. Al final del artículo puedes encontrar algunas referencias útiles con datos y opiniones sobre Archiva y Nexus. Con independencia de la elección, el objetivo del artículo es dejar claro para qué sirve y por qué nos es tan útil un software de gestión de repositorios. En nuestro caso particular, nos decidimos por Nexus porque usamos eclipse y pensábamos que tendríamos menos problemas si todas las herramientas estaban bien integradas por ser de la misma compañía: Maven, Nexus y m2eclipse.

La verdad, he de decir, que m2eclipse nos ha dado algún problema que otro, especialmente alguno  bastante gordo que nos retrasó en el conocimiento del plugin y cómo funcionaba (p.e.: la opción "Enable Workspace resolution" ha dado problemas en sucesivas versiones del plugin), pero nada que decir sobre Nexus: hasta el momento, perfecto.

Finalmente, SVN, Maven y Nexus conforman una tríada perfecta para empezar cualquier proyecto pequeño adoptando buenas prácticas y un mínimo de coordinación automatizada, permitiéndonos poder escalar a proyectos y grupos más grandes afinando más hacia la integración continua con una buena base.

Referencias:




martes, 9 de febrero de 2010

Desarrollo en equipo con SVN, Maven y Nexus (parte I)

Banco de experiencias (V)


El orden es el placer de la razón pero el desorden es la delicia de la imaginación.
-Paul Claudel.

El desarrollo de software aúna una fascinante mezcla de pensamiento divergente (o creativo) con conceptos técnicos y prácticas metódicas. Para que un desarrollador (y especialmente un equipo de desarrollo) alcance los mayores niveles de eficiencia y productividad, las herramientas utilizadas deben garantizar la seguridad del proceso, pero siempre de forma proporcional a la envergadura del proyecto y manteniendo compatibilidad con el proceso creativo sin ahogarlo. Hay herramientas libres que nos ayudan a mantener este este delicado equilibrio entre orden y libertad para todo tipo de proyectos de forma sencilla e impecable.

Éste, como el resto de los artículos de la serie "banco de experiencias", no pretende ser un artículo más de documentación sobre las herramientas aquí comentadas ni encontrarás tampoco el enésimo tutorial sobre el asunto. Hay mucha documentación en la red y a lo largo del artículo suelo ofrecer información y referencias suficientes para que puedas profundizar en el tema. La idea de estos artículos es exponer buenas prácticas y comentar mi punto de vista, basado en mi propia experiencia profesional, sobre la utilidad real y pragmática de los temas abordados. Sin demagogia rimbombante ni publicidad interesada. Simplemente la síntesis de mi experiencia subjetiva.

Subversion

Subversion (también conocido simplemente como svn) es probablemente el mejor sistema de control de versiones centralizado que existe. Sin entrar en la discusión Centralizado vs Distribuido (DVCS), lo que si está claro es que el control de versionado es un aspecto crítico de cualquier proyecto de software.

En todo caso, si has llegado hasta aquí y no has usado nunca un software de control de versionado (VCS) la recomendación es clara: úsalo. Debes usarlo. Aunque tu proyecto sea muy pequeño. Aunque sólo exista un desarrollador. Has de asumir que, de la misma forma y con la misma naturalidad que usas un IDE o un compilador, deberás usar un VCS. Es absolutamente esencial. Si ya tienes claro que hay que usar uno y has decidido usar uno centralizado (o simplemente sueles usar otro, como CVS, por ejemplo), la recomendación también es clara: usa svn. En la wikipedia puedes consultar por qué SourceForge.net, Apache o Google Code lo eligieron, así como la documentación y herramientas disponibles.

Como decía, un software de control de versiones es necesario aunque el proyecto sea pequeño ya que te garantiza un seguimiento de cambios que te puede ahorrar muchas horas de trabajo. Si tienes clara la diferencia entre un editor de texto y un procesador de texto, entenderás enseguida la diferencia de usar backups de tu directorio de código y usar un VCS. No obstante, hay otro aspecto importante de los VCS que no suele ser tan comentado (quizá por obvio) y es su dimensión como herramienta colaborativa. Si de forma individual es extremadamente importante, para un equipo es absolutamente imprescindible. Un equipo no puede trabajar de forma "decente" sin Subversion. La idea de no usar un VCS o de usar uno bloqueante (tipo Visual SourceSafe) es una pesadilla para no dormir: "¡eh, cuidado!, no toquéis que voy a tocar yo" "¡Oh, mierda!, ya ha tocado alguien. ¡A ver ahora cómo lo arreglamos!"... o "¡fulanito, desbloquea el fichero que necesito añadir un método de la clase!" "¡No, espera que termine!"... Qué pesadilla. Me recuerda a aquellas herencias arcaicas de los programas COBOL de no pasarte de la columna 73 y poner los asteriscos en la columna nº 7... Bufff.

Trabajar con svn en equipo es lo más parecido a hacerlo como si estuvieses tú sólo. Si las tareas están repartidas, los conflictos son muy poco frecuentes (para que existan, dos desarrolladores deben haber modificado la misma línea simultáneamente antes del último commit) y cuando los hay, se suelen solucionar en pocos segundos. Es muy gratificante comprobar cómo un equipo numeroso puede trabajar en una aplicacion Web (un tipo de proyecto con un alto grado de colisión y concentración de trabajo) de forma cómoda y fluida sin problemas.

Maven

Aunque llevamos oyendo hablar de Maven desde hace varios años (Maven tiene ya 8 años), la adopción hasta hace cuatro o cinco años ha sido puntual y conceptual. Es desde la aparición de Maven2 (con su nueva arquitectura revisada) cuando realmente empieza a incorporarse (aunque también de forma muy lenta) a los distintos proyectos open source y esto ha hecho que en la comunidad de desarrollo comencemos a interesarnos y a integrarlo en nuestros proyectos. A mucha gente le ocurre que, tras leer sobre Maven y Ant, entiende las diferencias entre ellas, pero no alcanza a concretar por qué es tan importante y para qué le sirve realmente (qué le aporta que no tenga ya). Para aclarar definitivamente este punto simplemente hay que preguntarse cómo realizamos el proceso de construcción (generación de empaquetados y otros artefactos) en nuestros proyectos, y esto nos dará la respuesta. Veamos las opciones:
  1. Construimos con nuestra herramienta de desarrollo (Eclipse, Netbeans, etc...).
  2. Construimos con un fichero (build.xml) ant que nos hemos hecho nosotros.
Si se trata de un pequeño proyecto de un sólo módulo (un war, un jar, etc...) y/o el ciclo de vida de la aplicación es muy reducido (es una pruebecilla nuestra, una pequeña aplicación de las que se hacen en casa en zapatillas, etc) no importa, claro. ¿Qué más da? La he hecho yo y podré volverla a construir con mi IDE favorito o con mi Ant dentro de un año cuando tenga que hacer un cambio. Incluso aunque cambie el IDE o cambie mi entorno, podré adaptarme a la situación sin más problemas, hacer las correcciones y volver a generar el empaquetado.

Ahora bien, si nos situamos ahora un escenario profesional, el tema cambia mucho. A continuación expondré los problemas que nos encontramos con esas formas de construir aplicaciones. Seguramente ya te habrás encontrado con ellos, y si no, es porque el proyecto no era lo suficientemente grande o, simplemente, es una cuestión de tiempo que te los encuentres.
  • Homogeneidad. Cada desarrollador tiene sus costumbres y sus ubicaciones (paths) para sus proyectos, librerías, ubicación del JDK, etc. Es difícil e incómodo homologar a todo un equipo de desarrollo en una única estructura de ficheros. Aunque Sun hiciese su propuesta de convenciones para proyectos (estructura y nombrado) hace mucho tiempo, casi ningún IDE lo respeta al 100%. Además, la heterogeneidad de los distintos Sistemas Operativos no hacen más que complicar la posibilidad de tener una estructura y ubicación homogénea para todo el mundo. Eso hace que los ficheros de proyecto (.nbproject, .project, etc) no puedan ser portados de unos desarrolladores a otros ni compartidos entre distintas máquinas. Esta estructura acaba teniendose que modificar manualmente en los distintos IDE's o en el fichero build.xml de ant. En el caso de los IDE's es particularmente grave, ya que la información de librerías, por ejemplo, descansa en la configuración local del IDE de cada desarrollador, que suele ser distinta para cada uno, con lo cual la construcción se torna algo tremendamente frágil y poco transparente.
  • Reproducibilidad. Necesitamos realizar tareas forma constante y estable nuestro proyecto: construccion, pruebas unitarias, informes, etc... Repetibles en el tiempo (hoy y dentro de un año) y en el espacio (en mi máquina de desarrollo, en integración, en preproducción...). Necesitamos fijar parámetros que no están implícitos en el proyecto en si y que acaban también fijados en los IDE's o en el script ant: versión de Java, versiones de librerías, destino de cada librería (sólo para compilar, sólo para desplegar con la aplicación, para compilar y desplegar...), ficheros de configuración, etc... Esto dificulta el mantenimiento y oculta información esencial del proyecto. Si el proyecto se sube a SVN y no lo volvemos a tocar en un año, a menudo nos encontramos con que las partes esenciales del proyecto han quedado ocultas en IDE's (o lo que es peor, se han perdido porque eran parte de la configuración local de un miembro del equipo) o permanecen en un script de ant poco amigable para modificar.
  • Gestión del cambio. Algo tan común como añadir una nueva librería al proyecto o realizar una actualización de una existente tiene demasiado impacto en el equipo hasta resultar ligeramente traumático: todos deben realizar las tareas de la descarga y localización de las librerías, la configuración de su IDE y de su proyecto y/o la adaptación de sus ficheros ant. Incluso un equipo de desarrollo con normas rígidas y paths homologados, además de sufrir esta falta de libertad, sigue estando expuesto a este tipo de problemas.
  • Gestión de dependencias (externas). Este es sin duda el aspecto más importante, por delicado, y por el impacto de sus consecuencias. Imagina el siguiente proyecto: un EAR compuesto por dos módulos WAR, tres módulos EJB y un par de módulos de de librerías comunes (jar). Uno de los desarrolladores añade al EAR una librería "A" que necesita uno de los módulos EJB y otro desarrollador añade otra librería "B" que necesita uno de los módulos JAR. Ambas librerías tienen sus propias dependencias: la librería "A" requiere de xxx-commons-2.3 y de asm-2.1, la librería "B" de yyy-commons (que a su vez depende de xxx-commons-1.5) y asm-3.0. Ya tenemos el problema servido. Como ya comenté en el artículo "Errores comunes de despliegue JEE", este tipo de problemas algunas veces sólo se presentan aleatoriamente, ya que el problema puede presentarse o no en función de la secuencia de carga del ClassLoader de la máquina de turno. Esto ocurre muchas más veces de lo que nos pueda parecer a simple vista, si bien en la mayoría de los casos los conflictos no plantean problemas porque muchas librerías mantienen una compatibilidad perfecta hacia atrás. En mi experiencia, es habitual que ocurra sin embargo con grandes frameworks tipo Hibernate, Spring, Struts, etc, con consecuencias muy desagradables. Sin Maven, la gestión de dependencias no la hace nadie, o lo que es lo mismo, se hace manualmente si el equipo de desarrollo es muy cuidadoso y está muy bien coordinado.
  • Gestión de dependencias (internas). Otro aspecto de los proyectos medianos con varios módulos interdependientes entre si es que, además de tener que realizar gestión de dependencias de librerías de terceros tenemos que gestionar nuestras propias dependencias. Por ejemplo, para el caso anterior, si ambos WAR necesitan de los proyectos JAR de librerías comunes, todos los desarrolladores de los WAR deberán tener también que tener los proyectos (código fuente incluído) de dichos JAR, para estar debidamente actualizados... O bien buscar otra forma de distribución manual de empaquetados que también exigirá un esfuerzo adicional de coordinación.

Como puedes suponer a estas alturas, Maven es una solución perfecta a todos los problemas comentados anteriormente (salvo para el último punto, para el que se requiere un colaborador, pero eso lo comentaré en la segunda parte). Maven es y sirve para muchas cosas (compilación, paso de pruebas unitarias, control de calidad, etc) pero, fundamentalmente, es la mejor herramienta de construcción posible. Hasta ahora, para una construcción lo más homogénea y reproducible posible necesitábamos unas normas (o convenciones) y ant. Pero ant es un lenguaje específico de dominio para la construcción de proyectos: te tienes que crear tus propios scripts basado en tus convenciones y el esfuerzo de mantenimiento es exponencial a la envergadura del proyecto. Maven ya te aporta ambas cosas: convenciones (sobre disposición de directorios de proyecto, por ejemplo) y todo el trabajo listo para usar sin tener que configurar nada. Con Maven puedes realmente bajarte unos fuentes y ejecutar un "mvn build" sobre el directorio que contiene el "pom.xml". Y tener en poco tiempo todos los empaquetados, un informe de construcción, pruebas unitarias realizadas, etc, etc.. con configuración cero.

No obstante, el punto fuerte (e incluso espectacular) de Maven es la gestión de dependencias: sólo por la gestión de dependencias transitivas que realiza de forma automática, ya merece la pena con creces. En este tema me recuerda a los repositorios de Ubuntu. Cuando quieres una librería, añades la dependencia y la versión que quieres de las disponibles y él se encargará de aprovisionarse de todas las dependencias transitivas adicionales.

Incluso aún respetando las convenciones de Maven (te las puedes saltar si especificas en el pom.xml cuáles son tus directorios) Maven te ofrece toda la libertad posible: permite que un equipo trabaje con IDE's heterogéneos: cada desarrollador con su IDE favorito. Lo único que debes subir a SVN son los fuentes y el pom.xml. Podrás construir el proyecto de forma repetible, independiente del IDE, ejecutar las pruebas unitarias y olvidarte de problemas de librerías.

Obviamente no te vas a olvidar de tu IDE o de ant. Toda esta maravilla de Maven tiene un precio: el rendimiento. Un build con Maven te lleva más segundos de los que estás dispuesto a considerar como aceptables para tu trabajo de desarrollo habitual. No es aceptable desarrollar realizando builds con Maven. Por lo menos para mi. Por eso yo continúo realizando los ciclos de iteración compilación-despliegue-pruebas con mi IDE. Maven lo dejo para realizar las construcciones, para subir a svn proyectos autónomos y autogenerables y para poder realizar las integraciones y las puestas a preproducción de una forma segura y repetible.


En esta primera parte he expuesto 2 de 3 de las herramientas más esenciales para el desarrollo en equipo de proyectos Java (especialmente JEE). En el siguiente artículo cerraré el círculo con la herramienta que falta: un gestor de repositorios de Maven. Y explicaré cómo, con tan sólo esas tres herramientas, tenemos un entorno de trabajo potente y seguro para equipos de tamaño mediano sin rígidas normativas ni procedimiento burocráticos.

Referencias:

(continuación: Parte II)

martes, 12 de enero de 2010

Alternativas gratuitas a MS Project

“Como nada es más hermoso que conocer la verdad, nada es más vergonzoso que aprobar la mentira y tomarla por verdad”. -Cicerón.

MS Project es un software de administración de proyectos para asistir a administradores de proyectos en el desarrollo de planes, asignación de recursos a tareas, dar seguimiento al progreso, administrar presupuesto y analizar cargas de trabajo, aunque la verdad es que el uso mayoritario se centra (y de forma generalizada también acaba) en una planificación/cronograma acompañada de un diagrama de Gantt que nunca cabe en el documento de "Plan de Proyecto" y acaba tan reducido que es difícil de apreciar.

El uso de este software y sus artefactos (especialmente los diagramas Gantt) materializan la ficción extendida de las métricas del software a la que me referí en un artículo anterior. Y es que el mundo empresarial, inmerso en sus propios vicios adquiridos autojustificativos, requiere de éste tipo de "justificantes" falsificados, de la misma manera que se recoge un justificante por visita médica: es probablemente inútil, de redacción incomprensible y caligrafía críptica, puede que hasta falso o adulterado... pero se ha hecho necesario para que continúe la cadena de responsabilidad indirecta.

El software en realidad es bastante útil, el problema es que, como explicaba en el artículo comentado, los artefactos generados con el mismo se presentan como una verdad inmutable, como un producto exacto y preciso fruto de la ciencia y la ingeniería cuando en realidad, en el mejor de los casos, son producto de unas buenas prácticas, una experiencia dilatada, un buen equipo, unas acertadas predicciones y una ración de buena suerte. ¿Por qué? Pues sencillamente porque estamos estimando, estamos realizando diversas predicciones del tiempo que tardan varias personas cualificadas en realizar tareas moderadamente complejas y débilmente definidas, teniendo en cuenta una enorme sucesión de suposiciones relacionadas e interdependientes entre sí, y entre esas suposiciones, unos requisitos de proyecto inmutables o congelados en el tiempo: es decir, una conjetura como la copa de un pino, aunque más o menos razonable y convenientemente adornada.

No obstante lo anterior, el software tiene su utilidad para ayudarnos a realizar y gestionar esas conjeturas y tener pronósticos lo más acertados posibles: podemos desglosar las tareas, conocer sus relaciones y dependencias, realizar asignaciones aproximadas, conocer el camino crítico, detectar riesgos, etc... Si esos cronogramas fuesen algo vivo, como lo son los requisitos y el resto de los factores durante el ciclo de vida del proyecto, y se actualizasen y ajustasen periódicamente, podríamos tener una buena herramienta para gestionar nuestras hipót... perdón, quiero decir, tareas.

Dicho esto, vamos al tema que nos ocupa: en muchos casos, el coste de adquisición de este software es desproporcionado con una utilización parcial (digamos al 30% como mucho) y eventual (¿menos de 2 o 3 veces al año?), así que, ¿hay alternativas gratuitas?. Vamos a ello.


OpenProj

Probablemente el más parecido funcionalmente a MS Project y una de sus mejores alternativas. Está disponible para Linux, Unix, Mac y Windows (hecho en Java). Es gratuito, multilenguaje y distribuido bajo licencia CPAL, ha sido elegido para su inclusión en la suite Star Office para Europa.

Como herramienta de trabajo es perfecto. Sólo un inconveniente con respecto a la generación de artefactos: la impresión/exportación del diagrama Gantt y otros informes es sólo personalizable en la versión que se distribuye como Software as a Service (SaaS): Projects On Demand. La buena noticia es que el coste de esta versión es apenas de unos unos pocos 15€ al mes.


Ganntt Project

Esta herramienta cumple con el famoso Principio de Pareto (o "regla del 80-20") en cuanto a la funcionalidad esperada: la mayoría de los usuarios de MS Project (yo diría que mucho más del 80%) apenas utiliza un 20% de su funcionalidad. Esta funcionalidad mínima es la que nos ofrece este software.

Sus capacidades de importación/exportación, así como la generación de artefactos (diagramas e informes) cubren los mínimos necesarios como para que esta herramienta sea suficiente para realizar cronogramas de proyectos pequeños y medianos.

Es totalmente gratuito, multilenguaje, y distribuido bajo licencia GPL 2.0. Como también está desarrollado en Java, está disponible para Linux, Unix, Mac y Windows.

He ido probando cada actualización que hacen al producto y desgraciadamente siempre me he encontrado con ciertas carencias y deficiencias típicas de un producto aún falto de madurez. Ligeramente "tosco" y sin apenas hot-keys, tenía deficiencias editando tareas en proyectos no demasiado grandes, pero con muchas relaciones y tareas jerarquizadas (a la hora de mover tareas dependientes en el tiempo, gestionaba mal las dependencias "fuertes" o "rígidas" dejándolas sin desplazar). Tampoco nunca encontré una forma de realizar una re-distribución de recursos en casos de reasignación.

No obstante, seguiré probando hasta poder disfrutar su madurez definitiva.

OpenWorkbench

Probé la versión 1.1.6 cuando salió, allá por 2006. Realmente quedé impresionado porque era realmente una excelente alternativa a MS Proyect. Especialmente me gustó la facilidad para presentar distintas vistas a modo de hojas de cálculo que permitían obtener costes y realizar cálculos en base a estimaciones con bastante facilidad.

El producto es gratuito y open source (aunque no he encontrado el tipo de licencia exacto) no obstante, no es un proyecto muy activo: no parece haber evolucionado en estos últimos 4 años. Lamentablemente sólo está disponible para para plataformas Windows y yo no uso ese tipo de plataformas desde hace varios años, así que no lo volví a probar desde aquella vez. No obstante, si usas Windows, te animo a probarlo (y sobre todo, a cambiar a Kubuntu, claro ;-).

Nota: es bastante posible que funcione con Wine, pero me seducen más otras opciones... ;-)

KPlato

KPlato es la aplicación para gestión de proyectos de la suite KOffice. Es el más ágil, ligero y fluido de todos los comentados hasta ahora, y tiene el aspecto elegante y sencillo propio de la suite de Office para KDE.

Al igual que comenté en otro post sobre alternativas a MS Visio, se nota que si bien aún no ha alcanzado un nivel de madurez equivalente al OpenProj (en la redacción de este artículo he probado la versión 0.6.3), es equivalente o superior a Ganntt Project en cuanto a funcionalidad y muy superior a todos los demás en cuanto a usabilidad y agilidad. Al igual que con el resto de paquetes de la Suite, KPlato tiene un futuro muy prometedor ya que el roadmap evolutivo del producto nos depara probablemente la mejor alternativa a MS Project completamente gratuita.
Con licencia GPL, y originariamente para Linux, está disponible para muchas plataformas actualmente, incluído Windows.



Como siempre, recomiendo probarlos todos (lo que vale para mi, no necesariamente tiene que valer para ti ;-), aunque yo me estoy apañando perfectamente con los tres. Incluso he llegado a importar un .mpp de MS Project, modificarlo y volverlo a exportar para generar un mini-site HTML con Ganntt Project (del cual podía extraer perfectamente las imágenes de Cronograma Gantt que necesitaba).




Related Posts Plugin for WordPress, Blogger...
cookieassistant.com