La gestione di transazioni in C++Una delle tante novita' introdotte dal C++ rispetto al C e' la gestione
delle eccezioni. Nella letteratura questo nuovo metodo di segnalare il
fallimento di una operazione viene descritto molto piu' elegante, stabile
e compatto dell'uso sistematico di return code come segnalazione di
completamento o errore.
Senza voler ridescrivere nel dettaglio i problemi legati all'uso delle
exceptions(1) per la gestione degli errori intendo soltanto
ribadire il problema di fondo. La parte complicata non e' in chi genera
(throw) o chi gestisce (catch), ma nei metodi di tutte le classi che
l'exception attraversa in maniera quasi asincrona durante il processo
di stack unwinding.
Stando attenti a come si scrivono i metodi e' possibile evitare di
perdere risorse in caso di exception (vedi uso di auto_ptr) ma le cose
si complicano notevolmente quando si considera lo stato logico in cui
l'oggetto o altri oggetti coinvolti in quanto manipolati prima
della throw devono restare.
Nella sua accezione piu' stringente la scrittura di un metodo compatibile
con le exception richiede infatti che in caso di generazione di una
exception nulla sia stato fatto per quanto riguarda lo stato logico
dell'oggetto.
In altre parole le condizioni devono essere identiche a quelle
precedenti la chiamata del metodo (eventuali diversita' non devono
essere visibili tramite l'interfaccia pubblica degli oggetti coinvolti).
Quello che in pratica sarebbe auspicabile e' la presenza di "transazioni"
simili a quelle disponibili sui DBMS relazionali.
Proprio partendo da quest'idea ho implementato una gestione di
transazioni in C++ che semplifica notevolmente l'uso di exception per
la segnalazione di errori.
Implementare commit/rollback in C++Per la realizzazione di un programma di gestione della produzione
sto implementando un server transazionale scritto in C++ che mantiene
una rappresentazione in memoria di tutti i dati gestionali.
Il server centrale espone dei servizi applicativi e i vari client
richiedono l'esecuzione di questi servizi tramite dei form di richiesta
opportunamente compilati.
I dati gestionali sono tenuti in memoria in una stuttura dati reticolare
e il codice delle transazioni si occupa eseguire le operazioni e a
restituire ai client i risultati richiesti.
Nel caso che durante l'esecuzione di una transazione si verifichi un
errore il server ripristina la situazione a prima che la richiesta
fosse stata ricevuta e informa del problema il client.
Le informazioni di tipo gestionale sono contenute in classi "stupide",
nel senso che gli unici metodi interni alle classi sono relativi alla
gestione della struttura dati stessa
(2) . In pratica le transazioni manipolano dati molto simili
alle catene di un database reticolare classico e le operazioni che
vengono eseguite sono l'assegnazione di campi di vario tipo o
l'assegnazione di puntatori.
Quello che ho fatto e' stato sostituire i campi dati con degli oggetti
"intelligenti" che fossero in grado di memorizzare in un registro
le variazioni effettuate. Per fare questo sono risultati molto utili
i template disponibili in C++.
(1) | Per una trattazione completa si veda l'interessante articolo
"Exception Handling: A False Sense of Security" di Tom Cargill
disponibile
online oppure la raccolta di problemi/soluzioni che da
quell'articolo sono stati tratti e raccolti nel libro "Exceptional
C++" di Herb Sutter ISBN=0-201-61562-2.
|
(2) | Non sono al momento un convinto fautore di un approccio
object oriented per l'analisi di procedure di tipo gestionale.
A mio parere nelle problematiche gestionali e' presente un forte
coordinamento di entita' con scarsa autonomia; distribuire questo
coordinamento su classi non semplifica l'analisi. In altre parole
il forte coupling presente nelle problematiche gestionali
rende l'approccio OO inutilmente dispersivo.
|