Try fast search NHibernate
29 June 2010
Alt.Net Hispano Vale!!
La novedad es que el sabado pasado, para llenar un sabado sin VAN, hicimos un Alt.Net café con un poco de ejercicio de TDD al estilo Maulo (que vendría a ser como me sale a mi).
El resultado es que nació un nuevo framework de validación que se espera nos sirva para involucrar más gente al mundo OpenSource y, tal vez, para generar otros ejemplos de varias herramientas y tecnicas que el mundo Alt.Net quiere mucho.
El video del encuentro, como siempre, lo pueden ver en el wiki de las reuniones .
El sitio del nuevo framework es http://vale.codeplex.com/ y su nacimiento fue grabado en un screencast:
24 August 2009
NHibernate battle
Sorry but I can’t write this in english.
Bueno el guerrero, como se dice en la ciudad porteña, “arrugó”.
Miren este lindo post y las dos páginas de comentarios. A parte el ataco personal a Oren (aka Ayende) está muy claro que el sitio nació con el intento de publicizar un producto comercial.
Mis preguntas fueron:
You said "We've shown our product wins almost all the competitors on CUD tests", which is "your product" ?
Can you confirm that the code of the test of "your product" represent the best optimization you can do ?
A nuestro aspirante guerrero, y comercial promoter, le costó un poco mandarme el link del producto comercial y a la segunda pregunta contestó de la siguiente manera:
No, obviously, I can't confirm this. It will be much better this month. On the other hand, all we did was enough to show there is a lot of room for performance optimizations.
En Buenos Aires eso se nombra : “arrugar”.
En otro blog el chico pide que quien le diga que su test de performance está muy cercano a un MDTD (Monkey Driven Test Development), y por lo tanto no significativo, me pide que nosotros seamos quien provea un test que represente la realidad, lo cual es muy grave. ¿Estamos hablando de alguien que pretende publicitar un producto comercial sin tener idea de como crear un test de performance usando casos reales? ¿Que tendría que esperarme de ese producto?
Mirando parte del test me quedó claro que, deliberadamente o no, nisiquiera aplicaron la best practices que están claramente descriptas en las reference de NHibernate y no solo no aplicaron cosas como la descriptas en esta wiki si no que directamente la pasaron como algo no suportado por NHibernate. Yo no se como son las legislaciones internacionales pero eso, en Italia, estaría penalizado como “publicidad engañosa”.
Igual hay que felicitar al chico porque : No importa que se hable bien o mal lo importante es que se hable del producto… alguien va a caer seguro.
15 July 2009
Introducción a ORM
Despues de la charla al MUG me quedó una tarea pendiente.
La presentación está disponible aquí.
Quien assistió a la charla ya sabe que hay dos errores… para quien no vino encuentrenlo (significa que están siguiendo lo que está escrito).
18 June 2009
Introducción a ORM
El día 26 de Junio daré una conferencia gratuita en el Microsoft User Group (MUG) de Buenos Aires.
El objetivo de la charla es la introducción a los conceptos de ORM que están a la base de persistent layers como NHibernate, EntityFramework y otros.
Los temas que trataremos son:
- Conceptos básicos de ORM
- Técnicas de POID
- Técnicas de mapeo de herencia
- Técnicas de mapeo asociaciones/agregaciones
- Implementaciones de Concurrencia
- Uso de StoredProcedure/Triggers
- Características destacadas de un PersistentLayer
Si piensan usar/escribir un persisten layer o tienen en mente asistir a un curso sobre algún framework especifico, basado en ORM, asistir a esta conferencia es aconsejable.
Para quien quiera asistir les dejo el link.
17 June 2009
Spanish Inflector.Net
Después del recibir feedback sobre el post anterior (gracias a Jorge y Hadi) he hecho algunos cambios a la implementación del Inflector.Net.
El primer cambio fue el volver atrás con la implementación del Tablize o sea que ahora trabaja pluralizando solo la última palabra (así como prevé la convetion de RubyOnRails). Este cambio hace que el SpanishInflector cubra más del 70% de las traducciones desde el nombre de la clase al nombre de la tabla.
Fue interesante probar la implementación sobre sistemas existentes. Este es el código que usé:
public void Naming()
{
var si = new SpanishInflector();
var cfg = new Configuration().Configure();
foreach(var pc in cfg.ClassMappings)
{
var tn = pc.Table.Name;
var en = StringHelper.UnqualifyEntityName(pc.EntityName);
var tableize = si.Tableize(en);
if (!tableize.Equals(tn))
{
Console.WriteLine("{0} - {1} [{2}]", en, tn, tableize);
}
}
}
Lo que resultó interesante fue el hecho que al usar el Inflector nos hubiéramos dado cuenta que algunos nombres de tablas están equivocados y hasta saltaron algunos nombres de clase equivocados.
Llegar al 100% de cobertura, y traducción exacta, es un poco difícil ya que se interponen nombres compuestos por dos, tres o más palabras y pluralizar solo la ultima, a veces, no es suficiente y a veces es equivocado (así como pluralizar todas). Hago algunos ejemplos:
Clase | Tabla |
| OrdenCliente | OrdenesClientes |
| TipoDocumento | TiposDocumento |
| FormaPago | FormasPago |
| PagoForma | PagosFormas |
| DocumentoTipoProducto | DocumentoTiposProductos |
A parte el hecho que, en algunos casos, se entra en la no opinable “cuestión de gustos” (léase formas distintas de llamar la misma asociación) no he encontrado un patrón que permita definir exactamente cuáles son las palabras que hay que pluralizar, ni hablar de cuando la clase está compuesta en cocoliche (palabras en Español y palabras en Inglés).
Ya que queda claro que una convención o se aplica siempre, aunque no nos guste, o jamás puede cubrir el 100% de los casos agregué la posibilidad de un data-dictionary o agregar reglas propias a la convención de default (solo la última palabra es la que se pluraliza).
Agregar una entrada en el data-dictionary es así:
AddDataDictionary("UsuarioRol", "UsuariosRoles");
o si quieren
inflector.AddDataDictionary("UsuarioRol", "UsuariosRoles");
En los días a venir encontraré el tiempo de “postear” sobre el uso del spanish-inflector para el INamingStrategy de NH (quien piensa usarlo en FNH es probable que ya sepa cómo usarlo).
26 May 2009
Para que ?
Hay veces que me pregunto para que escribir posts sobre como empezar con NHibernate.
Hoy vi una perlita:
Un query statico (siempre el mismo) escrito usando Criteria API y pocas lineas mas abajo un query dinamico (cambiante según determinada condiciones) escrito usando string concatenation para generar un HQL, y como postre, ambos en un DAO static.
Será que tampoco le pego cuando escribo en español ?
10 May 2009
Alt.NET Argentina meeting
Una reunión interesante con intercambio de idea y experiencias. La organización fluyó como el aceite.
En lo personal participé a:
- UIX
- Open source Made in Argentina
- Tecnicas ORM
- DDD
La reunión sobre Open-source se desvirtuó un poco, respecto a lo que me esperaba, ya que hablamos mas de algunos aspectos del mismo más que de OS made en AR, pero bueno ese es el espíritu del open-space e igual me sirvió mucho.
Tengo unos apuntes con nombres de tools que me llevará un tiempito investigarlos todos.
De 18 a 21 hubo un Open-space, a cielo abierto con cerveza y cenicero, con la participación de la máquina de Jhonny Halife y me parece que a esa reunión no le cabe otro título que “Tools brain storm”.
Un agradecimiento especial a Carlos Peix y Martin Salias.
01 May 2009
Empezando con NH: mappings
| Posts anteriores: | Empezando con NHibernate Configuración Session |
El mapping es el “leguaje de programación” de NHibernate. Cada línea de mapping se compila en el momento de construir el session-factory (configuration.BuildSessionFactory).
Hasta antes que saliera NH1.2.0 la regla que divulgaba, para el mapping, era “decile a NH lo que ya sabes; no lo hagas trabajar demás”. Esta regla funcionaba muy bien en tanto uno supiera que es lo que le está diciendo a NH. Mientras trabajábamos en NH2.0.0 me di cuenta que el copy&paste es una actividad muy usada, escribiendo mappings, y el resultado, en muchos casos, era un desastre (especialmente si no se miran las SQLs generadas). Estaba claro que había que trabajar para cambiar la regla.
La regla maestra para escribir mappings (a parte de conocer bien las técnicas de ORM) es:
“No aclares que oscurece”
Este es un mapping que uso en mis cursos:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Starting.NH"
namespace="Starting.NH.OptimisticLock.Revision">
<class name="Task">
<id type="int">
<generator class="hilo"/>
</id>
<version name="Version"/>
<property name="Description"/>
</class>
</hibernate-mapping>
Notar que el “type” del POID está allí solo porque la implementación de la entity no tiene una propiedad para el ID.
Cuando uno empieza con NHibernate lo primero que busca es “algo” que escriba los mappings; me pasó también a mi (recuerdo haberle dedicado un par de horas, pero todo empezaba por las tablas). Como le he contado en un post anterior trabajar con NH y no conocer ORM no es una opción y lo peor que pueden hacer es generar los mappings usando como origen las tablas. Si buscan generadores de mappings busquen algo que trabaje con un DSL que describa su entorno de negocio.
Ahora viene lo difícil… El mapping de NH es muy flexible y la cantidad de combinaciones posibles es muy, pero muy, grande; intentaré definir una serie de recomendaciones más bien genérica.
Las recomendaciones
- Estudien las técnicas de ORM; los mappings son ORM aplicado. No todo es <subclass> así como tampoco todo es <joined-subclass>.
- No aclaren que oscurece; escriban lo menos posible. Con que la sintaxis sea correcta, por lo general, alcanza.
- Copien el file nhibernate-mapping.xsd en las “external lib” del proyecto y no en las carpetas de VisualStudio.
- Mientras escriban el mapping usen siempre el schema; el intellisense es una masa y hay que aprovecharlo.
- Trabajen por diferencia; si saben que un valor es el default no lo escriban (por ejemplo el default para el nombre de la columna es el nombre de la propiedad).
- No usen unsaved-value si van a escribir el default del type del Id o de la versión y, en lo posible, no inventen cosas raras solo para escribir un unsaved-value (si un id jamás puede ser cero ¿que razones hay de usar otro valor? )
- Definan assembly y namespace en el header del mapping (ver ejemplo arriba).
- Si abren un mapping y le cuesta leerlo (le duelen los ojos) es porque no cumplieron con la regla maestra.
- No usen default-cascade=”save-update”; el cascade hay que declararlo bien y donde corresponde.
- Si van usar implementaciones de IUserType, IUserCollectionType o IUserVersionType usen el tag <typedef>.
- Escriban todos queries estáticos en el mapping y no en el código; los queries en el mapping sobre todo son compilado, son intercambiables entre HQL y SQL, las características de comportamiento se definen en el mapping (por ejemplo por lo que concierne la cache).
- Recuerden que el cascade no es un solo valor (es comma-separated-values) y no es todo all-delete-orphan.
- Usen default_schema, default_catalog de la configuración del session-factory y los attributes schema, catalog, del header del mapping solo si trabajan multi-rdbms.
- Usen los tags DDL oriented (como length, precision, scale, not-null etc.) cuando corresponde. Escribir “string(100)” o “Double(18,5)” tambien es bueno.
- No usen el nodo <column> si no es necesario; casi siempre los attributes del nodo <property> alcanzan.
- Para las collections no existe solo <bag>; estudien los otros tipos de collections.
- No le tengan miedo al <set>; cuando Microsoft nos escuche y ponga una interface parecida a ISet usaremos la del framework. Notar que usar Iesi.Collections no significa poner una dependencia a NH en sus entidades, para nada, a parte que en la entity pueden usar ICollection<T> mapeado a un <set>.
- Si piensan necesitar los tags where, order-by, formula asegúrense de no estar delegando cuestiones de negocio a NHibernate y tengan en mente que de servidor de DB hay uno, y es caro, y de servidores de aplicación hay varios y son más barato.
Fluent-NHibernate
Fluent-NH es una opción para escribir mappings pero todas las recomendaciones anteriores siguen valiendo. Tengan presente que Fluent-NH genera XML y que el XML generado hace doler los ojos. Por otro lado Fluent-NH no suporta todas las features que suporta el mapping XML así como el mapping XML no suporta todas la features que se pueden implementar usando C#.
No soy adivino y no sé qué pasará cuando empezaremos NH3.0.0. Lo que si se, es que NH tendrá su mapping basado en fluent interface (Loquacious como lo llamamos en NHV) y que no generará XML (creará directamente los meta-data).
30 April 2009
Empezando con NH: session
| Posts anteriores: | Empezando con NHibernate Configuración |
Cuando se empieza a trabajar con NH uno de los escollo es el manejo de sesiones; tal vez sea el más grande. La realidad es que hay muy poco que elegir y así muy poco que estudiar.
Los patrones de manejo de sesión son:
- Open session in view (aka session-per-request)
- Request, session y transaction tienen el mismo ciclo de vida
- Session-per-Conversation (aka long-session)
- Permanece abierta por más de un request
- Conversation-per-Business Transaction (CpBT)
- Permanece abierta por el tiempo que dura una transacción de negocio
- Session-per-Call (anti pattern)
- Permanece abierta por el tiempo que dure un query, o un save, o un update…
- Session-per-application
- Imposible usar en una aplicación real
- Más que un pattern es una “Time bomb”
Sobre los último dos no vale la pena gastar ni una línea.
Con Session-per-Conversation (eschema disponible aquí) hay que tener cuidado porque no siempre funciona como uno se espera (léase abrir dos tabs en lugar que dos instancias de browser). Hay frameworks que facilitan el uso de session-per-request en mix con session-per-conversation y limitan la cantidad de conversations iniciadas a una. A mi gusto quedan sesión-per-request y conversation-per-business transaction (eschema disponible aquí).
Si pueden organizar la aplicación para usar session-per-request siempre, sería una buena solución. Si notan que los use-case, que necesitan una trasaction de negocio que involucra más de un request, son muchos, vayan pensando que session-per-request, en algún momento, le puede quedar corto. Si la aplicación es WinForm o WPF olvídense de session-per-request por el simple motivo que en esos ambientes no existe nada parecido a un request (ni siquiera el Call-context lo es).
Las recomendaciones
- Recuerden que la session implementa UnitOfWork; la implementación del pattern UnitOfWork es la session de NHibernate.
- Traten de mantener en la session lo que realmente se necesita que esté en la UnitOfWork; el Flush podría ser muy laaargo.
- “Abracen” todas acciones de persistencia con una transaction, no importa que sean de lectura o escrictura.
- Haganse la idea que la ISession no es la IDbConnection.
- Haganse la idea que la ITransaction no es la IDbTransaction.
- No encierren la ISession en una clase con Save, Update, FindBy etc., es completamente innecesario; en el DAO/Repository usen la ISession.
- Si algo "no funciona" ante de pensar que sea un bug de NHibernate intenten escribir un test que reproduzca el error afuera de su aplicación (NH es muy usado, en el mundo, en varios entornos y en aplicaciones comerciales).
- Antes de escribir su session-handler averigüen quien ya lo hizo; no intenten inventar, ya somos muchos los que han golpeado la cabeza, ustedes, en lo posible, evítenlo.
- Asegúrense que su capa de acceso a datos (DAO o Repository) permita cambiar la estrategia de gestión de sesiones de persistencia; por ejemplo inyectando ISessionFactory a su DAO y usando GetCurrentSession(tambien se puede inyectar la ISession pero, en ese caso, asegúrense de conocer lo que pierden).
- Eviten que sus DAO/Repository tengan referencia a un session-handler especifico (aunque suene similar no es lo mismo del punto anterior); en lo posible mantengan la implementación de DAO/Repository pegada solo y exclusivamente a NH.
- Recuerden que el manejo de sesiones de persistencia es algo más cercano al manejo de cuestiones de infraestructura.
- Al primer problema relacionado con lazy-loading asegúrense usar una estrategia de manejo de sesiones adecuada al caso de uso.
- Si piensan necesitar un ISession.Evict preocúpense; es posible que el manejo de sesiones no sea el adecuado. Ni hablar si ven una aplicación con Evict por todos lados. El Evict es útil solo en algunos casos especiales.
- Sepan que ISession no es solo Get, SaveOrUpdate, CreateQuery y CreateCriteria.
- Investiguen porque parece que NH tiene dos métodos para hacer lo mismo; Get y Load no son lo mismo.
- Aprendan a trabajar con entidades desconectadas (ISession.Lock, ISession.Merge)
- Averigüen de qué se trata con IStatelessSession.
Donde encontrar session handlers
La primer fuente es NHibernate mismo. El name space NHibernate.Context contiene la clase WebSessionContext para manejo de sessiones en WEB y ThreadStaticSessionContext para manejo de sesiones en tests. Usando WebSessionContext no necesitan nada mas (a parte una implementación de IHttpModule) para manejar session-per-request y/o session-per-conversation en entorno WEB. Notar que las implementaciones disponibles en NHibernate se basan en el uso de GetCurrentSession y son descripats en NHibernate in Action.
Castle y Spring.NET ofrecen “semplificadores” de manejo de sessiones en WEB, WinForm y tests.
RhinoTools ofrece una implementación para WEB (session-per-request y/o session-per-conversation).
NHibernate.Burrow provee varias formas de manejo de sesiones orientado a WEB. Burrow tambien implementa algo muy similar a CpBT o mejor dicho implementa session-per-conversation sin limitaciones a una sola convesación por HttpSession.
uNhAddIns implementa todos los patterns. Como la implementación en NHibernate-Core tambien las implementaciones en uNhAddIns se basan en el uso de GetCurrentSession. Las implementaciones son disponibles en el namespace uNhAddIns.SessionEasier y uNhAddIns.Web.SessionEasier. La implementaciones de session-per-request y session-per-conversation ofrecen un uso “semplificado” respecto a las implementaciones en el core de NH ya que el Bind/Unbind es automatico (el Unbind automatico se activa solo si aceptan usar algún DynamicProxy, por ejemplo el mismo que usan en NH). Para lo que concierne la implementación de CpBT los invito a leer varios posts. Como ultima nota, sobre uNhAddIns, les aclaro que uNhAddIns no trae dependencias a algo mas que no sea NHibernate, todas las implementaciones de session-handlers pueden ser usadas a solas o con el IoC/AOP que prefieran.
29 April 2009
Empezando con NH: configuración
| Posts anteriores: | Empezando con NHibernate |
De aquí en más, cuando haga referencia a NHibernate (NH), usaré NH2.1.0.
NH es un framework muy flexible y por ese motivo la configuración de la session-factory es bastante extensa; sin embargo nadie nos obliga a usar o definir un valor para todas las features suportadas por NH. Acá les muestro la configuración que uso para mis cursos de introducción a NHibernate:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="StartingNH">
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.connection_string_name">StartingNH</property>
<property name="connection.isolation">ReadCommitted</property>
<property name='proxyfactory.factory_class'>
NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu
</property>
<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
<property name="adonet.batch_size">50</property>
<property name="command_timeout">10</property>
<property name="format_sql">true</property>
</session-factory>
</hibernate-configuration>
Esta configuración puede ser usada tranquilamente en producción. Para su entorno de desarrollo, tal vez, sea mejor usar la propiedad connection.connection_string en lugar que user connection.connection_string_name.
En realidad una configuración perfectamente valida es:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.connection_string">
Data Source=localhost\SQLEXPRESS;Initial Catalog=BlogSpot;Integrated Security=True
</property>
<property name='proxyfactory.factory_class'>
NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu
</property>
</session-factory>
</hibernate-configuration>
Como verán son tres las cosas que NH necesita para poder funcionar:
- El Dialect del RDBMS que vamos a usar (y hasta eso es opciónal pero bueno…)
- La connection string
- El sistema de DynamicProxy que usará para trabajar en forma transparente con lazy-loading.
No me digan que esa es una configuración compleja.
Hay otra parte de la configuración que, no es de NH pero, es importante en fase de desarrollo/tests: la configuración de log4net.
Acá va una muestra:
<log4net debug="false">
<appender name="console" type="log4net.Appender.ConsoleAppender, log4net">
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" />
</layout>
</appender>
<appender name="CleanConsole" type="log4net.Appender.ConsoleAppender, log4net">
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%m%n" />
</layout>
</appender>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender,log4net" >
<param name="File" value="NHibernateLog.txt" />
<param name="AppendToFile" value="false" />
<param name="RollingStyle" value="Date" />
<param name="DatePattern" value="yyyy.MM.dd" />
<param name="StaticLogFileName" value="true" />
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
<root>
<priority value="WARN" />
<appender-ref ref="RollingFile" />
</root>
<logger name="NHibernate.SQL">
<level value="OFF" />
</logger>
<logger name="NHibernate.Tool.hbm2ddl.SchemaExport">
<level value="ERROR" />
</logger>
</log4net>
Para quien no conoce log4Net aclaro que lo que está siempre activo son dos niveles de log: el WARN (warning) y el ERROR para el SchemaExport que es para quien usamos NH tambien para generar el DB schema en fase de tests.
Las recomandaciones para NH
- Eviten usar frameworks que "ocultan" la configuración de NH; enrollar un XML con otro XML no tiene sentido (hasta que alguien demuestre lo contrario).
- Si quieren usar algún framework que permita la configuración por codigo asegurense que lo haga heredando de NHibernate.Cfg.Configuration y/o usando una implementación de IHibernateConfiguration y no generando otro XML.
- Nombren la/las session-factory especialmente si trabajan en multi-rdbms. El nombre de la session-factory puede ser la key para encontrar la session-factory asociada a un determinado DAO/Repository.
- Definan siempre el isolation level aunque cada Drive tenga ya su default; los valores admitidos son definidos en System.Data.IsolationLevel.
- Usen el tag <mapping> para agregar sus mappings a una configuración.
- No olviden definir query.substitutions; evitarán sorpresas cuando ejecuten HQLs en donde especifiquen valores de clases (true,false) y no valore de DB (1 o 0).
- Si saben que su drive suporta la ejecución de queries en batch (más de un queries en un solo round-trip) definan adonet.batch_size; si no lo definen el batcher no se activa y la diferencia en performance puede ser notable.
- Definan el command_timeout (en segundos) a un valor congruo para su aplicación; en mi forma de endender si un comando SQL lleva mas de 10 segundos algo anda mal.
- Controlar alguna SQL generada por NH puede ser un desafió no de poco (especialmente cuando le toman la mano al ORM). Configurar format_sql a true le permitirá ver las SQL en un formato mas human-readable (NO todo en una sola linea).
- En desarrollo usen el file hibernate.cfg.xml y una base de datos local y no usen el App.config y base de datos común para los tests; cada desarrollador tiene el derecho de tener la base en local con su connection-string y hacer debug sin preocuparse de bloquear a los otros desarrolladores. El file hibernate.cfg.xml tendrá que ser excluido del repository de fuentes (svn:ignore) mientras que se puede incluir un file hibernate.cfg.template para que cada desarrollador tenga un ejemplo.
- No activen la cache (aka second level cache) hasta que la applicación no tenga por lo menos una versión en producción. La cache no es la panacea de las performance; una applicación debe funcionar bien sin cache… luego le pondrán el “turbo” si y donde lo necesita.
Las recomandaciones para el logging
- No olviden configurar el logging de NHibernate.
- Ya que lo tendrán activo no olviden leerlo; en NH nos costó bastante definir algunos niveles de log y si se loguea un WARNING, en casi todos los casos, es porque hay que prestar attención a algo que está pasando. Ni hablar si el log es un ERROR.
- Cuando escriban behavior-tests, con o sin WatIn, activen el log “NHibernate.SQL” a DEBUG y miren las SQL que NH está generando. Este proceso es indispensable en fase de optimización de la applicación.
- Por lo mismos motivos del file de configuración de NH usen un file tambien para la configuración de log4net (no usen el App.config) y escluyan ese file del repository de fuentes; cada desarrollador tiene el derecho de activar los logs que necesite.
28 April 2009
Empezando con NHibernate
Desde que Microsoft empezó a divulgar Linq2SQL y Entitity-Framework la cantidad de empresas y programadores que usan NHibernate aumentó notablemente. Quiero aprovechar la ocasión para intentar definir algunas líneas guías que ayuden a iniciarse con NHibernate (NH para los amigos).
En este post empiezo… despacito iremos avanzando juntos.
¿Qué es NHibernate?
NHibernate es un framework de persistencia basado en ORM (Object Relational Mapping).
Que NH se base en ORM significa que conocer la técnica de ORM es fundamental, no es una opción.
En la red se pueden encontrar varios recursos sobre ORM, a mi gusto, los mejores son los escritos por Scott Ambler. Si piensan no tener tiempo de leer "Agile Database Techniques" no hay problemas pero no se pierdan una de sus White-paper que subí en los files de varios fórums.
Que NH sea un framework de persistencia significa que tienen que pensar en NH como algo que ejecuta queries SLQ (ejecuta INSERT, UPDATE, DELETE, SELECT). NH simplifica el acceso a datos y NO debería tener mayores responsabilidades que eso. Si entendieron esta simple definición entenderán que preguntas como "¿puedo usar NH con WPF?" o "¿NH funciona con WCF?" o "¿Hay algo para usar NH en WinForm?" son preguntas con muy poco sentido porque sería como preguntarse si pueden usar una clases de ejecute queries en cada uno de esos ambientes.
Tal vez una definición más cercana a la realidad es: NHibernate es un DAL (Data Access Layer).
Las técnicas de ORM nacieron exactamente para abstraer el acceso a DataBase relacionales en una capa que resuelva el acceso a datos. Lo que hay que tener en cuenta, en esta afirmación, es la palabra capa (Layer). En este caso "capa" identifica un estrato lógico de nuestra aplicación. Nuestra aplicación será completamente orientada a objetos (entidades de negocio) y nuestro DAL se ocupará de transformar esos objetos en instrucciones SQL para gestionar el estado persistente (los datos de cada entidad de negocio que nuestra aplicación deberá recordar).
De aquí naces algunas recomendaciones:
- No intenten usar NH en una aplicación que no esté bien dividida en capas lógicas.
- No hagan comparaciones entre usar ADO.NET, con data-binding, con usar NH; sería como paragonar un auto terminado con un motor.
- No piensen en tabla-fila-columna; piensen, primeramente, en entidades de negocio, propiedades y relaciones.
- Nunca olviden que todo termina en una base de datos relacional; empezar con objetos y pensar OO no significa que tengamos que olvidarnos que el data base existe.
- Empiecen definiendo las clases y, con la ayuda de un DBA, definan su representación persistente (siguiendo las reglas de ORM) y luego definan el mapping. En mi caso personal yo suelo definir la representación persistente directamente escribiendo el mapping.
- Usen como mínimo SchemaValidator y comparen siempre el schema que generaría NH con el schema que definieron ustedes.
- Escriban behavior-tests de persistencia y controlen las SQL generadas por NH.
20 March 2009
Alt.NET LA
Señores acaba de nacer Alt.NET en Latinoamerica o por lo menos en Argentina.
El google-group está aquí.
Estamos charlando sobre la organización de la primera reunión así que si tienen temas que les interesan están invitados a subscribirse al grupo y… deje su mensaje despues de la señal.
La verdad que con tantos proyectos Open Source, en los que colaboramos residentes en Argentina, no tener un Alt.NET acá era un desperdicio.
Señores… primer paso hecho ahora empieza el baile.
12 December 2008
28 November 2008
NHibernate: CALIDAD no se logra por casualidad
En estos últimos meses he visto, más de una vez, una serie de lindos “dibujos”, con colores, que pretendían demostrar la dudosa calidad de NHibernate. Como, por mi edad, he superado, ya hace tiempo, la celosía sobre código producido, la primera vez que vi ese análisis me pareció interesante sobre todo para aplicarla a algún otro proyecto. Todas las otras veces (7 u 8 en 5 meses) que vi ese link, con comentarios tipo “good luck to NH team” o “NH team should fix this problem”, ya empezó a parecerme un poco pesado sobre todo porque se evidencia un “posible problema”, una y otra vez, sin ocuparse de mostrar una “posible solución”. Tengo toda la sensación que se está usando NHibernate como medio para publicitar un producto comercial en lugar de hacer una crítica para mejorar NHibernate; si hubiera otra intención veríamos, adjunto a la crítica, una propuesta de cambios (por este motivo no publico el link a ese producto).
Les quiero dar mi personal opinión sobre la calidad de NHibernate analizándolo desde otro punto de vista; los hechos.
“por peso”
NH2.0.0 tuvo más de un año de desarrollo con más de 100.000 líneas de código entre modificadas y nuevas respecto a la versión anterior. NH2.0.1 tuvo más de 20.000 downloads en menos de 2 meses. NH2.0.x tiene más de 1400 tests entre tests unitarios y behavior-tests. En el team nadie tiene permiso de crear aunque sea un branch-official donde se pueda romper un solo test.
NH2.1.0 es el nombre de la próxima versión (el actual trunk). Por suerte, o tal vez por confianza y calidad, NHibernate tiene bastantes usuarios del trunk. NH2.1.0 posee casi 1600 tests que operan sobre más de 1100 clases por un total de casi 180.000 líneas de código C#.
¿Qué resultado da todo esto?
A hoy 80 bugs (o posibles bugs) de varios niveles, y más de 100 issues entre pedidos de nuevas features y mejorías; que representa 80 sobre la cantidad de lo que hay atrás, y las funcionalidades que NH ofrece, se lo dejo calcular a ustedes.
No sé a cuanta gente les preocupa como está hecho NH por adentro (a parte que para juzgarlo hay que conocerlo bien) pero que hasta el trunk se pueda considerar estable no es poca cosa.
Conclusión
La CALIDAD no se logra por casualidad; la calidad de un software se logra con muchos tests, reglas férreas en el team, y manteniendo la conciencia y el anhelo de mejorarse todos los días.
27 November 2008
La encuesta se terminó
Después de un mes la encuesta “How you are testing your persistence” se terminó.
La muestra no es para nada significativa y por lo que veo de los estadísticos de Google, sobre visitas a este blog, queda evidente que son muy pocos lo que le interesa dar a conocer como trabaja.
Lo resultados fueron:
Unit tests of entity and it's mapping 16 (53%)
From DAO / Repository 13 (43%)
From Model 1 (3%)
From user Interface 0 (0%)
Por lo menos me puedo quedar tranquilo que nadie votó por “From user Interface”.
07 November 2008
La concorrenza é l’anima del commercio
Que linda frase es esa: La competencia es el alma del comercio.
Hace un tiempo largo en NHibernate implementé IProxyFactoryFactory (porting, con adaptación, desde Hibernate). Como me está pasando, últimamente, nadie entendía para que “esa cosa” es necesaria, hasta que un día un committer me escribe en privado diciéndome: “al final hay alguien que entiende para que hiciste ese trabajo” y me engancha un link. El link llevaba al blog de William C. Pierce que usó IProxyFactoryFactory junto a un tool para generar proxies que pudieran trabajar en médium-trust. Junto con la movida que hicimos para dar a la luz NH-Forge, Bill Pierce, no solo aceptó entrar en NHibernate-Contrib si no que aceptó “rever” su trabajo y cambiarle de nombre a NHibernate.ProxyGenerators (notar el plural). Hasta ese entonces el plural era, lamentablemente, solo una mera intención…
Un día, de la nada, aparece un branch en NH-Core que llevaba todo el código de NH y una implementación de un ProxyFactoryFactory para usarlo con PostSharp (come venia pensándolo hace un tiempo); el problema del branch es que todavía estaba todo incrustado a parte que no pasa la mayoría de los tests de NH. Quédense en este día porque fue el disparador…
En todo este periodo había unos asuntos que me estaban molestando no poco:
- Pocos son lo que entienden que el hecho de declarar métodos “virtual” no es una invasión de NH.
- NH parecía no funcionar si no existiera Castle.
- Quien usa Spring igualmente se tiene que llevar Castle.
- En Castle no quieren liberar release y quieren que todos trabajemos con el trunk.
- NH tenía una dependencia a algo sin versiones.
- La gente que usaba NH con Castle Windsor y/o ActiveRecord se volvía loca al intentar mantener todos los proyectos sincronizado.
De buen tano calentón que soy (tano=Italiano en Buenos Aires) ese día me cansé y decidí dedicar el día a “separar los tantos” y la mañana siguiente pude anunciar la anhelada separación de dependencia desde Castle.DynamicProxy2 versión x.y.z (cualquiera porque no tiene, nunca fue liberado desde casi dos años).
Bueno… lo único que faltaba era solo empezar a generar alternativas… Den una vista a este link, al fondo, y fíjense cuan larga fue esta historia; falta muy poco para que cumpla un año. Hoy puedo anunciar la primera alternativa a Castle.DynamicProxy2 en NHibernate. Nació NHibernate.ProxyGenerators.LinFuDynamicProxy.
LinFuDynamicProxy será, probablemente, la alternativa que usarán quien no usa ningún IoC-FW en su proyecto ya que es una sola DLL, pesa 23KB (para NET3.5) y tiene una leve mejora en performance respecto a Castle (no estoy completamente seguro pero me pareció midiendo los tiempos de ejecución de los tests de NH).
Para quien usamos IoC falta un paso; ¿no se imaginan cual? No sé exactamente para cuando, pero espero pronto sea disponible NHibernate.ProxyGenerators.SpringDynamicProxy.
¡A ver si se logra trabajar con algo que tenga versión! ;-)
Technorati Tags: NHibernate,ProxyGenerators,Castle,LinFu,Spring
18 October 2008
El placer de un Bug Fix
Después de tantas líneas de código escritas en NHibernate (según las estadísticas de ohloh van más de 130000 solo en el core de NH) aún encuentro placer en arreglar bugs.
El placer se incrementa cuando, rastreando un bug, me encuentro con comentarios bastante detallados en puntos críticos donde, por varios motivos, había tomado una determinada decisión sobre la implementación de una funcionalidad de Hibernate3.2. En el caso de NHibernate, que es un porting, estas cosas son las que denomino: licencias poéticas. La misma definición la uso cuando alguien toma un patrón y lo implementa como le parece.
En NH encontré y arreglé unas cuantas licencias poéticas y, despacito, despacito, me permití también tomarme mis licencias poéticas (hay veces que el TDD te lleva a eso).
Realmente es un placer cuando aparece un bug que me lleva a arreglar una licencia poética y más aún si también me permite transformar un TODO en DONE… ni hablar si eso arregla dos bugs de un solo fix.
14 October 2008
Allí vamos
Antes o después tenía que pasar que me animara con esta cosa de “blogguear”.
Estuve pensándolo un tiempo largo… cual sería el titulo, que idioma, que temas tocar, vale la pena, me gusta más escribir C#, no tengo tiempo… bueno todas esas cosas juntas.
Para el idioma queda bastante claro que como principal elegí el español o tal vez mejor sería definirlo “cocoliche” ya que seguro se me va a mezclar el porteño de Buenos Aires con el italiano de mi tierra madre y el inglés que voy escribiendo bastante seguido.
Hace un año había abierto un blog, siempre usando los servicios de mi querido Google, que duró unos 20 minutos. Lo que pasó en estos días es que me animé a escribir algo en www.nhforge.org y parece que le tomé el gusto. El empujón final, para abrir un blog personal, me lo dio un amigo lejano que nunca vi personalmente (así son las cosas ahora, viste).
Y bueno… con este post empieza la bailanta a ver que sale.