viernes, 22 de junio de 2007

persistencia: la clase persistible

...quiere decir una clase cuyos instancias (objetos) puedan salvar su estado en un medio persistente (como un archivo o base de datos) para un momento posterior se pueda recrear ese objeto.

Me propongo en esta ocasión guardar el estado de los objetos en alguna base de datos (los ejemplos aquí expuestos están en MySql).

Miremos primeramente el lado de la base de datos (el modelo relacional). Me enseñaron en la Poli lo importante que es el álgebra relacional y la normalización, que se resume en la definición de las tablas, una clave primaria, una o más clave alternas y externas así como cuidar de la integridad relacional entre tablas. Todo esto mas un buen criterio en modelamiento es la base de conocimiento de todo niño informático que dice de sí mismo ser un “hacker”.

Hace años, en algún momento aprendí que era mejor no perder tiempo en la búsqueda una clave primaria, y dejar que cada tabla tenga una columna con valores enteros únicos a la que se la llama “Id” y que sea éste campo la clave primaria. Se incrementa en 1 cada vez que se agrega un nuevo registro. Esto no impide que invierta mi tiempo en buscar índices en base a claves únicas que son la base de la eficiencia.

Por ejemplo: en una tabla con la información de licencias de manejo al menos tendrá dos claves: Id, que es la clave primaria, y el número de licencia que es una clave alterna única. Crear un nuevo registro impone un nuevo valor Id sobre una base secuencial (máximo Id + 1). Actualizar un registro significa buscarlo en base al campo Id para actualizarlo. Cargar un registro implica aplicar un criterio de búsqueda, encontrarlo y recordar su Id con el propósito de actualizarlo o borrarlo. A esto voy a agregar otra columna de control,”version”, de tal manera que cada que ejecute una sentencia sql “update…” este campo se incrementa en la unidad.

     create table licencia (
         Id int,
         version int,
         numero varchar(16),
         -- otros campos
   primary key(Id));
     )

 (ingresando datos tendríamos...)

  +------+---------+------------+- - -
  | Id   | version | numero     | ....
  +------+---------+------------+- - -
  |    1 |       1 | 2190033333 |
  |    2 |       1 | 9012227615 |
  |    3 |       1 | 7810289387 |
  +------+---------+------------+- - -

Miremos ahora la definición de la clase (para variar... en groovy). Si quiero que un objeto sea persistible, entonces no se me ocurre otra cosa que replicar los campos “Id” y “version” del modelo relacional a la definición de clase:

  1  class licencia {
  2      int Id
  3      int versión
  4      String numero
  5      // ... otros campos
  6      // ... otros métodos
  7  }

Esta clase no debería contener sentencias SQL relacionadas con persistencia para mantenerla como elemento del dominio de la aplicación, que absorba todo la complejidad de la lógica de negocios sin mezclar código de persistencia.

Entonces... ¿dónde está el código que carga (load), guarda (save) o elimina (delete) un objeto?, en otra clase llamada licencia_ORM que contiene todos esos métodos, y que debería manejarse a nivel de comandos:

  1  licencia_ORM orm = new licencia_ORM()
  2  licencia lic = new Licencia()
  3 
  4  lic = orm.load('Id = 1')
  5  //
  6  // operaciones del dominio de negocios sobre el objeto 'lic'
  7  //
  8  orm.save lic

para los iniciados

Por algunas razones prefiero este esquema de persistencia a algunos frameworks:

  • Menos dependencias
  • La clase licencia_ORM es generable y es el punto claro donde defino las sentencias SQL de persistencia.
  • Excepto por los campos “Id” y “version” la clase licencia en el dominio de negocios está alejada de anotaciones que afectan la visibilidad del código.
  • Se me ocurre que aspectos de la clase licencia_ORM pueden ser controlados mediante "metaclase" en groovy.
  • Este mecanismo lo utilicé inicialmente en Delphi y créanme ¡ jamás me ha fallado !

miércoles, 20 de junio de 2007

persistencia

Persistencia es el "arte" de almacenar y/o recuperar el estado de un objeto, y el estado de un objeto es el valor de los campos de una objeto (mil disculpas si algún purista se siente incómono con estas definiciones).

No todo campo de un objeto requiere persistir, puede ser calculado, en tal caso a ese campo se lo llama trasciente. Por ejemplo si tengo una clase que representa un triángulo rectángulo entonces el estado a almacenarse corresponderá a los dimensión de los lados, mientras que la hipotenusa es un campo trasciente ya que resulta de aplicar la eterna ecuación pitagórica.

¿Pero cómo se almacena un objeto?, la respuesta puede ser tan sencilla como por ejemplo implementar un método "save()" en una clase de tal manera que abra un archivo, escriba allí el valor de cada campo, y luego cierre el archivo. Luego si requiero recuperar el estado de un objeto, leo desde el archivo el estado de los campos previamente almacenados. Pero es sabido que si se pretende almacenar la información en una base de datos, por las facilidades de indexación los métodos "load()" y "save()" no van a ser muy tribiales.

Una serie de metodologías y patrones se aplican bajo la denominación "Mapeo Objeto-Relacional" (en Inglés Object Relational Mapping - ORM). Esta denominación tiene algunas implicaciones la principal es aquella que nos dice que el modelo de negocios es un modelo de objetos (orientado a objetos) mientras que el almacenamiento es un modelo relacional. Cuando un objeto persiste movemos el estado de un modelo a otro.

A pesar de la eficiencia alcanzado por los RDBMS como MySql, DB2, Oracle, Sql Server, etc. El modelo relacional parece algo superable a largo plazo, es decir que pasará algún tiempo hasta que tengamos un producto serio y seguro para almacenar (persistir) objetos sin recurrir al modelo relacional. Por el momento ORM significa bastante. Un programador con mediana experiencia puede sospechar y deducir mentalmente alguna metodología para almacenar objetos, pero el tema se puede tornar tan escabroso y complejo que hoy por hoy tenemos algunos frameworks, como Hibernate e iBatis. Si se ha dado una vuelta por la librerías habrá notado el grosor de libros de Hibernate, pero si quiere saber que tan debatido y profundo es el tema le recomiendo este interasantísimo artículo.

martes, 19 de junio de 2007

¿.Net o Java?

...quiere decir una clase cuyos instancias (objetos) puedan salvar su estado en un medio persistente (como un archivo o base de datos) para un momento posterior se pueda recrear ese objeto.

Me propongo en esta ocasión guardar el estado de los objetos en alguna base de datos (los ejemplos aquí expuestos están en MySql).

Miremos primeramente el lado de la base de datos (el modelo relacional). Me enseñaron en la Poli lo importante que es el álgebra relacional y la normalización, que se resume en la definición de las tablas, una clave primaria, una o más clave alternas y externas así como cuidar de la integridad relacional entre tablas. Todo esto mas un buen criterio en modelamiento es la base de conocimiento de todo niño informático que dice de sí mismo ser un “hacker”.

Hace años, en algún momento aprendí que era mejor no perder tiempo en la búsqueda una clave primaria, y dejar que cada tabla tenga una columna con valores enteros únicos a la que se la llama “Id” y que sea éste campo la clave primaria. Se incrementa en 1 cada vez que se agrega un nuevo registro. Esto no impide que invierta mi tiempo en buscar índices en base a claves únicas que son la base de la eficiencia.

Por ejemplo: en una tabla con la información de licencias de manejo al menos tendrá dos claves: Id, que es la clave primaria, y el número de licencia que es una clave alterna única. Crear un nuevo registro impone un nuevo valor Id sobre una base secuencial (máximo Id + 1). Actualizar un registro significa buscarlo en base al campo Id para actualizarlo. Cargar un registro implica aplicar un criterio de búsqueda, encontrarlo y recordar su Id con el propósito de actualizarlo o borrarlo. A esto voy a agregar otra columna de control,”version”, de tal manera que cada que ejecute una sentencia sql “update…” este campo se incrementa en la unidad.

     create table licencia (
         id int,
         version int,
         numero varchar(16)
         -- otros campos
     )

 (ingresando datos tendríamos...)

 +------+---------+------------+--- - - -
 | Id   | version | numero     | ....
 +------+---------+------------+--- - - -
 |    1 |       1 | 2190033333 |
 |    2 |       1 | 9012227615 |
 |    3 |       1 | 7810289387 |
 +------+---------+------------+--- - - -

Miremos ahora la definición de la clase (para variar... en groovy). Si quiero que un objeto sea persistible, entonces no se me ocurre otra cosa que replicar los campos “Id” y “version” del modelo relacional a la definición de clase:

class licencia {
    int Id
    int versión
    String numero
    // ... otros campos
    // ... otros métodos
}

Esta clase no debería contener sentencias SQL relacionadas con persistencia para mantenerla como elemento del dominio de la aplicación, que absorba todo la complejidad de la lógica de negocios sin mezclar código de persistencia.

Entonces... ¿dónde está el código que carga (load), guarda (save) o elimina (delete) un objeto?, en otra clase llamada licencia_ORM que contiene todos esos métodos, y que debería manejarse a nivel de comandos:

licencia_ORM orm = new licencia_ORM()
licencia lic = new Licencia()

lic = orm.load('Id = 1')
//
// operaciones del dominio de negocios sobre el objeto 'lic'
//
orm.save lic

para los iniciados

Por algunas razones prefiero este esquema de persistencia a algunos frameworks: