miércoles, 20 de mayo de 2009

Open Source BRE/BRMS JSR-94 compliant

El título está en inglés, pero es que "Motores de Reglas de Negocio o Sistemas de Gestión de Reglas de Negocio compatibles JSR-94 de código abierto" es un título muy largo y, cuando buscamos información, se suele buscar más usando los términos en inglés.

Recientemente he tenido sondear el estado del arte de los BRE/BRMS de código abierto y lo primero que encontré es que hay decenas (concretamente hay 30 en esta lista de noviembre de 2007). Obviamente, no tengo tiempo de evaluar tantos proyectos, así que establecí una serie de criterios de búsqueda que me redujesen la lista de resultados a una cantidad aceptable para evaluar o, al menos, leer y recopilar información para una posterior evaluación.

Los criterios de búsqueda que establecí son:
  • BRE mínimo (se excluyen "compiladores" de reglas)
  • Conformidad con la JSR-94
  • Proyecto activo (considero "activo" un proyecto con actividad reciente inferior a 2 años)
  • Ligero, con persistencia y repositorio autónomo (es decir, que aunque pueda usar una base de datos no la necesite necesariamente)
  • Documentación suficiente o aceptable.
El resultado de la recopilación es:
  • Drools / JBoss Drools / Jboss Rules
  • OpenRules
  • Hammurapi Rules
  • SweetRules
  • JRuleEngine

Aunque muchos BRE evolucionan a un BRMS, lo cierto es que BRMS no hay muchos, con lo que la recopilación se queda en un número más pequeño del que me imaginaba. Además, el criterio de conformidad a la JSR-94 ha sido suficientemente restrictivo, ya que excluye todos los que no son Java y además, son muy pocos los que cumplimentan la especificación.


Drools (JBoss Drools / JBoss Rules) 
Probablemente el más conocido, y también el más gigantesco de los proyectos. Se puede considerar un BRMS en toda regla ya que tiene herramientas típicas de los BRMS propietarios (repositorio, editor de reglas WUI,etc)
Las reglas pueden escribirse en DRL (el típico), Java, Groovy... incluso puede extenderse con DSL's vía XML.
Para mi, quizá uno de los puntos fuertes de Drools sea la integración con el resto de servicios de middleware de jBoss, especialmente con jBPM. La versión 5, se espande en un elenco de servicios realmente impresionante, que promete bastante.
Curiosamente, tiene  un porting a .NET.


OpenRules
Este es el proyecto que más me ha llamado la atención por novedoso, curioso y de aplicación práctica inmediata. Desdel el punto de vista de la existencia (y variedad) de repositorios y herramientas, estamos ante un BRMS (Drools y éste son los únicos de la lista). La característica más destacada de OpenRules es la versatiliidad y adaptabilidad, ya que:
El sitio web está muy bien organizado, tiene muchos ejemplos, y la documentación es bastante buena. Me ha impresionado, realmente.

Como curiosidad, está votado como el más popular en javarules.org.


Hammurapi Rules
Es más un BRE que un BRMS, aunque tiene una arquitectura multithread muy bien diseñada. Una ventaja interesante es que el lenguaje elegido para las reglas es el propio Java, con lo que la curva de aprendizaje es muy pequeña. Además, siendo realistas, pocas situaciones hay en las que existe el famoso "analista de negocio" que es capaz (y además quiere hacerlo) de definir las reglas de negocio en un lenguaje "informático" (y eso suponiendo que los objetos de negocio no cambien mucho).

Me parece una buena opción para casos en lo que nos biene especialmente bien escribir las reglas en Java y queremos "empotrar" un BRE en nuestra aplicación fácilmente. Por ejemplo, para migrar a una aplicación con muchas reglas hard-coded a reglas modificables en caliente sin demasiado impacto.

SweetRules
Aunque no es conforme a la JSR-94, me llamó la atención que es el único que implementa RuleML, el que se propone como lenguaje de reglas estándar. No obstante, la web es caótica, y la documentación deja mucho que desear. La implementación de RuleML es la única curiosidad.

JRuleEngine
Probablemente es el BRE más ligero de los 5. Las reglas se escriben en XML y no he visto que implemente Rete. No obstante, parece cumplir con los mínimos.


Al final, junto con Drools (¿cómo no?) el proyecto que más me ha gustado es OpenRules. Hammurapi Rules también es bastante interesante. ¿Crees que he omitido alguno que debería estar? ¿hay alguno que te parezca especialmente interesante? Agradeceré comentarios al respecto.

lunes, 18 de mayo de 2009

Alternativas EAV con XML (en PostgreSQL 8.3)

El modelo EAV
El modelo Entidad-Atributo-Valor (EAV, Entity-Attribute-Value), también conocido como Objeto-Atributo-Valor o Esquema Abierto, se usa en casos donde el número de atributos (propiedades, parámetros) usados para describir una entidad u objeto es potencialmente grande, pero que aplicados individualmente a una entidad concreta es pequeño. Las circunstancias donde se suelen aplicar son:
  • Entidades con atributos heterogéneos:
    • Entidades dinámicas en el tiempo, donde los atributos de una entidad son fijos, pero durante un período de tiempo variable. Es decir, son cambiantes (pueden crecer o decrecer) en el tiempo.
    • Entidades conceptualmente dinámicas, dependiendo de la interpretación del sistema en un determinado momento. Es decir, entidades cuyo número de atributos cambia según el contexto (p.e.: atributos definidos por el usuario)
  • Entidades con atributos homogéneos muy poco densos. Es decir, entidades con una desproporción muy grande entre el número de atributos posibles y el número de atributos con valor (no nulos).
Entidades en escenarios típicos de este tipo de modelos son, por ejemplo:
  • documentos (en una base de datos documental) cuyos atributos asignados a cada documento depende de la empresa, departamento, tipo de documento, etc...
  • información cuya catalogación adicional depende de parámetros definidos por el usuario
  • conceptos de negocio o abstractos cuyos atributos dependen de varios factores y varían en el tiempo: "expediente", "valoración", "indicencia", etc...
Este modelo se suele resolver sobre el modelo relacional con tres tablas: la de entidad, la de atributos posibles de dicha entidad y la de valores. La información se registra conceptualmente en la tabla de valores, que relaciona la información a través de tres columnas: clave ajena de entidad, clave ajena de atributo y valor.

Incidencia
Id Fecha
1 17/05/19 22:10
2 18/05/19 10:13
3 18/05/19 17:05
Datos
Id NombreAtributo
1 Longitud
2 Temperatura
3 Volumen
4 Sector
DatosIncidencia
IdInc IdDato Valor
1 1 5
1 4 A
2 2 6
2 3 4
2 4 A

Los problemas que aporta este modelo son:
  • Consultas SQL complejas (muchos "CASE"), que en algunos casos deben usar herramientas típicas de datawarehouse (PIVOT, crosstab, etc), para convertir en columnas lo que, en realidad, son filas.
  • Tipo de dato único para todos los atributos, sean numéricos, fechas o cadenas, que luego deberán convertirse, o complicar el modelo con distintas tablas de atributos en función del tipo de dato.

XML y Xpath al rescate
Una buena alternativa a este tipo de problemas es implementar un campo con XML y procesarlo con herramientas XPath. Lamentablemente, el tipo de dato XML de PostgreSQL 8.3 aún no tiene operadores de comparación ni se pueden crear índices sobre este tipo de dato, pero se puede tratar como String y indexar expresiones XPath como veremos a continuación.

La ventaja de usar XML es que podemos contar con un número de atributos variable encapsulados en un documento XML en un sólo campo y evitar tener que usar el modelo EAV, por ejemplo:  

Incidencia
Id Fecha DatosIncidencia
1 17/05/19 22:10 <data><longitud>5</longitud><sector>A</sector></data>
2 18/05/19 10:13 <data><temperatura>5</temperatura><volumen>4</volumen><sector>A</sector></data>
 
Con una tabla como la anterior, podemos realizar consultas sencillas con XPath, tipo
SELECT xpath('/data/temperatura/text()', DatosIncidencia)
FROM incidencia
que nos permite un control total en la consulta de atributos sin complicadas consultas. Puede haber quien le parezca que XPath es complicado y que no se gana tanto, pero en mi opinión, es más sencillo tratar con un único campo y una única tabla aunque tengamos que realizar un pequeño aprendizaje de XPath. A la larga, todo es más simple: tanto las consultas como el mantenimiento.

También se pueden optimizar ciertas consultas comunes creando índices, aunque usando algún truco.

El soporte de XML "de serie" en PostgreSQL no ha hecho más que empezar, y le queda un gran camino por recorrer, pero ya estamos en disposición de empezar a aprovecharlo.


Referencias y más información:

viernes, 8 de mayo de 2009

Banco de experiencias (II): Logback, la evolución de log4j

Log4j se ha convertido en el estandar de facto para la información de trazado de cualquier proyecto Java. Es una de esas librerías que se añaden a un proyecto prácticamente en el propio proceso de creación del mismo, antes de añadir ninguna clase. Pertenece a ese pequeño y selecto grupo de librerías/frameworks imprescindibles (me lo apunto para una próxima entrada) en cualquier proyecto. Y cuando digo cualquier proyecto, no sólo me refiero a Java. El diseño de la librería y de su estructura es tan bueno, que ha sido portada a multitud de plataformas: el porting de .NET es excelente, y tiene otros muchos más a diversas plataformas.

Sin embargo, a pesar de parecer perfecta y casi inmejorable, tiene un sucesor muy superior: logback. Lo primero que uno percibe al examinar logback es que su diseño y realización está basado en la experiencia con log4j, mejorando algunos pequeños inconvenientes que habían surgido durante su evolución y, sobre todo, respondiendo a las necesidades que han ido surgiendo durante estos casi 10 años de vida, como demuestra Ceki Gülcü, su diseñador, que fue también el fundador de log4j.

Simple Logging Facade for Java
Logback es una implementación de SLF4J (Simple Logging Facade for Java): una capa de abstracción (un façade, como su propio nombre indica) para varios frameworks distintos de logging. SLF4J es el sucesor de Jakarta Commons Logging (JCL), pero mejorado en muchos aspectos. Sin entrar en demasiados detalles, para cualquiera que realice una migración a SLF4J disfrutará, de entrada con 3 mejoras inmediatas:
  • Se acabaron los problemas con los class loaders, dada su vinculación (binding) estática con la implementación subyacente (con JCL es dinámica en tiempo de ejecución).
  • Trazado con parámetros mucho más sencillo y eficiente.
  • Independencia, dado que puedes usar múltiples vinculaciones con sólo añadir otro ".jar" (p.e.: desde "slf4j-simple-x.x.x.jar", para pequeñas aplicaciones que usen System.err hasta "slf4j-log4j12-x.x.x.jar", para servir de puente a log4j.)
Logback
Logback, al ser una implementación sofisticada de SLF4J, disfruta de todas las ventajas de éste y, también sin entrar en sofisticaciones y sólo tocando temas comunes que cualquier usuario habitual de log4j podrá valorar, yo destacaría las siguientes:

Migrando desde log4j
Los impacientes que quieran empezar a usarlo migrando un proyecto existente, pueden considerar usar el SLF4J Migrator, muy útil para hacer los cambios en pocos minutos.

Los que hayan usado log4j sin seguir las normas de estilo, como trazar sin mensaje (p.e. log.trace(a), siendo "a" un int, boolean, Exception o cualquier otro objeto) deberán resolver los errores de compilación, ya que SLF4J no soporta esto: deberán poner un mensaje siempre (al fin y al cabo, si no se pone, la traza queda poco legible).

En todo caso, por experiencia, os garantizo que la migración es bastante suave y se puede cambiar un proyecto en pocos minutos.


Fichero de configuración
En log4j me había realizado un fichero de configuración más o menos estándar para entornos de producción que me generaba 3 ficheros:
  • Uno de nivel INFO. Uno por día, sin borrado automático (lamentablemente no era posible con el DailyRollingFileAppender)
  • Uno de nivel DEBUG. Fijo por tamaño y con máximo de ficheros
  • Uno de nivel TRACE. Fijo por tamaño y con máximo de ficheros.
Esta configuración me resultaba muy útil, ya que en caso de incidencia reciente, tenía logs de niveles TRACE y DEBUG de las últimas horas del sistema. El problema es que tienes que ser muy prudente con los tamaños y había que navegar entre varios ficheros para encontrar el momento que buscabas.

He migrado el fichero a logback pero pudiendo disfrutar de las características nuevas: excepciones más cortas en INFO, uno por día en todos los niveles (aunque con menos historia en los niveles más verbosos).

Os dejo el fichero a continuación para que podáis echar un vistazo y adaptarlo a vuestras necesidades.

logback.xml
1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 <configuration>
 4   <jmxConfigurator contextName="tkuf2" />
 5   <!-- Se puede establecer el directorio "a mano" o usar el del usuario  -->
 6   <!-- <property name="USER_HOME" value="/home/szarza" />  -->
 7   <property name="USER_HOME" value="${user.home}" />
 8   <property name="appName" value="tk.uf" /> 
9   <property name="logPath" value="${USER_HOME}/tk2/logs" />
10   <!--
11     1 por día. Nivel INFO. 300 días de historia 
12    -->
13   <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
14     <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
15       <level>INFO</level>
16     </filter>
17     <File>${logPath}/${appName}.log</File>
18     
19     <!-- 5 líneas de stacktrace para las excepciones -->
20     <layout class="ch.qos.logback.classic.PatternLayout">
21       <Pattern>%date %-5level %logger{20} - %message%n %exception{5}</Pattern>
22     </layout>
23     
24     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
25       <FileNamePattern>${logPath}/${appName}.%d{yyyy-MM-dd}.log</FileNamePattern>  
26       <!-- mantener 300 días de historia -->  
27       <MaxHistory>300</MaxHistory> 
28     </rollingPolicy>
29   </appender>
30   
31   <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
32     <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
33       <level>DEBUG</level>
34     </filter>
35     
36     <File>${logPath}/${appName}.d.log</File>
37     
38     <!-- 10 líneas de stacktrace para las excepciones -->
39     <layout class="ch.qos.logback.classic.PatternLayout">
40       <Pattern>%date %-5level %logger{20} - %message%n %exception{10}</Pattern>
41     </layout>
42     
43     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
44       <FileNamePattern>${logPath}/${appName}.d.%d{yyyy-MM-dd}.log</FileNamePattern>
45       <!-- mantener 10 días de historia -->  
46       <MaxHistory>10</MaxHistory> 
47     </rollingPolicy>
48   </appender>
49 
50   <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
51     <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
52       <level>TRACE</level>
53     </filter>
54     <File>${logPath}/${appName}.t.log</File>
55     
56     <!-- full stacktrace para las excepciones -->
57     <layout class="ch.qos.logback.classic.PatternLayout">
58       <Pattern>%date %-5level %logger{20} - %message%n</Pattern>
59     </layout>
60     
61     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
62       <FileNamePattern>${logPath}/${appName}.t.%d{yyyy-MM-dd}.log</FileNamePattern>  
63       <!-- mantener 5 días de historia -->  
64       <MaxHistory>5</MaxHistory> 
65     </rollingPolicy>
66   </appender>
67 
68   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
69    <layout class="ch.qos.logback.classic.PatternLayout">
70      <Pattern>
71         %date{HH:mm:ss.SSS} %-5level %logger{10} - %message%n
72       </Pattern>
73     </layout>
74   </appender>
75   
76   
77   <logger name="cestel.tk.uf" level="TRACE">
78     <appender-ref ref="INFO"/>
79     <appender-ref ref="DEBUG"/>
80     <appender-ref ref="TRACE"/>
81   </logger>
82   
83   <root level="OFF">
84     <!-- 
85     <appender-ref ref="STDOUT" />
86      -->
87   </root>
88   
89 </configuration>

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