ActiveRecord
Una panoramica sull'implementazione in .NET dell'omonimo pattern per la persistenza degli oggetti.

I. Cosa è ActiveRecord

IntroduzioneLo sviluppo di applicazioni che si interfacciano con database per memorizzare e recuperare dati porta inevitabilmente lo sviluppatore a scontrarsi con la profonda differenza che intercorre tra il modello a oggetti e il modello relazionale, costringendolo alla scrittura di diverse centinaia di righe di codice - spesso ripetitivo - per gestire la persistenza dei propri oggetti in maniera più o meno complessa in base alle necessità e togliendo tempo prezioso a una maggiore cura della logica business dell'applicazione. Un enorme aiuto in questo senso è arrivato con l'introduzione degli ORM, strumenti che offrono raffinati automatismi per la gestione della persistenza degli oggetti e un alto livello di astrazione nell'accesso ai database. In ambiente Java il più famoso è senza dubbio Hibernate e il mondo .NET può contare su un suo riuscitissimo porting, NHibernate. Si tratta di uno strumento sicuramente molto potente e flessibile ma anche abbastanza complesso e spesso questa sua caratteristica può farlo apparire inadatto ed esageratamente laborioso per essere adottato nello sviluppo di applicazioni di piccole o volendo anche medie dimensioni, ma non eccessivamente complesse nella loro struttura dati. Fortunatamente esiste anche un approccio più semplice e rapido che può tornare molto utile in casi come quelli descritti e consiste nell'applicazione del pattern Active Record attraverso una libreria per .NET sviluppata nell'ambito del Castle Project chiamata, appunto, ActiveRecord.

Il principioLa libreria ActiveRecord implementa il pattern omonimo dove un oggetto rappresenta una riga in una tabella/vista di un database, ne incapsula l'accesso e aggiunge una logica di dominio a quel dato: da qui la definizione di record attivo. In questa maniera ogni metodo di classe (metodi statici, nel nostro caso) agisce sul set intero di record nelle tabelle, per esempio al fine di ricercare le istanze di una classe, mentre ogni istanza è responsabile delle relative operazioni di  CRUD (Create, Read, Update and  Delete). Nella pratica la logica base di accesso al database e delle operazioni di CRUD viene implementata e messa a disposizione da una classe astratta (ActiveRecordBase) che viene ereditata ed estesa dalle classi che rappresentano gli oggetti da persistere, in più per rendere ancora più elastica l'adozione di questo pattern la libreria lo "estende" fornendo una serie di attributi per definire associazioni e integrando in maniera nativa anche i pattern Single Table Inheritance e Class Table Inheritance per risolvere velocemente i problemi di ereditarietà nella maniera più congeniale. In generale questo approccio si dimostra più immediato rispetto al pattern Data Mapper sfruttato da NHibernate dove invece vi è un layer che si occupa di isolare gli oggetti in memoria dal database gestendone il trasferimento tra i due e dove ci si ritrova a dover stilare le mappature manualmente tramite file di configurazione XML (che non è assolutamente necessaria con ActiveRecord poichè si basa su auto-mappature o codice esplicito piuttosto che su file di configurazione). E' doveroso far notare che la potenza e l'efficenza di NHibernate sono veramente notevoli grazie anche al linguaggio HQL e all'implementazione di pattern comportamentali come Lazy Load, Identity Map e Unit of Work... che però sorprendentemente può vantare anche ActiveRecord per una ragione molto semplice: il cuore di questa libreria è rappresentato proprio da NHibernate stesso! Come potremo vedere in alcuni dei prossimi articoli questo ci permetterà di sfruttare tutte le ottimizzazioni già consolidate messe a disposizione da NHibernate (dirty checking, cache di primo e secondo livello, lazy loading delle collezioni, sessioni e transazioni) in maniera assolutamente trasparente e quindi con più rapidità di sviluppo ma con in più la possibilità per lo sviluppatore, se necessario, di raggiungere il cuore della libreria stessa e quindi di utilizzare direttamente NHibernate all'interno dei suoi Record Attivi per gestire problematiche più complesse.

Qualche considerazioneLo sviluppo nell'ambito di casistiche di semplice o media complessità dello schema relazionale, soprattutto lavorando con database nuovi e non già esistenti, può risultare nella maggior parte dei casi più rapido e agevole usando ActiveRecord rispetto al gettarsi in toto su NHibernate, tuttavia c'è qualche considerazione da fare:
  • La libreria è ancora in beta nonostante sia già abbastanza completa e funzionante, mancano ancora alcune feature che in realtà sarebbero comode come per esempio il supporto per le chiavi composte (ovvero formate da campi multipli), tuttavia nella roadmap è previsto di implementare tutti gli scenari di accesso ai dati più comuni.
  • Sicuramente rappresenta un'alternativa più semplice a NHibernate ma utilizzando quest'ultimo al suo interno ovviamente non la rende un'alternativa più leggera. Sfrutta tutte le ottimizzazioni di NHibernate, ma il motore interno risulta comunque molto complesso, in più i tempi di inizializzazione dell'applicazione risultano leggermente più lenti con ActiveRecord.
  • Ogni tanto mi è capitato di riscontrare una certa perplessità proprio per il fatto che con ActiveRecord si deve ereditare dalle sue classi base e occorre adornarle con attributi, non avendo quindi una classe estranea da logica di accesso al database e di operazioni di CRUD come si ha invece con NHibernate. Questo viene visto principalmente come ostacolo alla scalabilità o al refactoring in certi ambiti, ma a voler ben vedere quante sono le applicazioni che necessitano di considerazioni simili? Molte volte si parla di applicazioni, principalmente web, che non arrivano minimamente a livelli di complessità tali da richiedere per forza di cose un utilizzo diretto e pieno di NHibernate e trarrebbero invece giovamento da una contrazione dei tempi di sviluppo pur mantenendo alti livelli di stabilità.
Proprio questo ultimo punto è il motivo principale per cui il pattern active record è stato sfruttato con successo per strutturare la componente di persistenza dei dati in Ruby on Rails, un framework scritto in Ruby per lo sviluppo rapido di applicazioni web con struttura MVC che ultimamente si fa sempre più spazio nelle discussioni tra gli sviluppatori web nonostante la sua giovane età (poco meno di un anno) grazie alla sua facilità, rapidità di sviluppo e quindi produttività. L'implementazione di active record per .NET è nata proprio nel contesto di un porting di Ruby on Rails chiamato MonoRail (precedentemente conosciuto come Castle on Rails) sempre sviluppato dal Castle Project e supportato da una community particolarmente attiva.

Nel prossimo articoloIn questo primo articolo ho voluto preparare una breve introduzione su ActiveRecord confrontandolo direttamente con NHibernate per fornire ai lettori una prima idea delle differenze che ci sono tra questi due strumenti di ORM. Nei prossimi articoli mi soffermerò quindi su questa libreria, ponendo NHibernate in secondo piano citandolo solo dove necessario e puntando a link esterni per approfondimenti adeguati