Wednesday, November 7, 2007

Nausea nazionale (once was "Orgoglio nazionale")

Massimo Mantellini (Manteblog) cita oggi Michele Serra (de La Repubblica).
Io cito Mantellini che cita Serra:
"Non so come sia farsi assassinare negli altri Paesi, ma farsi assassinare in Italia e' il peggio che puo' capitare. In conseguenza del fatto che la cronaca nera e' un genere di successo, il cadavere diventa una specie di proprieta' pubblica"

Sinceramente? Serra ha perfettamente ragione e Mantellini pure.
Io? Mi limito a cercare di diffondere una lucida analisi (e direi anche condanna) della triste e nauseabonda situazione in cui versano i maggiori quotidiani nazionali. E praticamente tutti i TG (fatto salvo il TG3, ma un po ne risentono anche loro a volte). E si "inizia" a nausare anche sul web.

Volevo concludere con una battuta, ma non me ne vengono: ho sempre pensato che una situazione non diventi veramente grave finchè si riesce a fare una battuta su di essa.

Io oggi sullo stato delle coscienze italiane non riesco a far battute.

Sunday, November 4, 2007

PDF whitepaper: "Tecniche di 'boxing' e 'schermatura' per basi di dati SQL Server 2005"

Il PDF di questo whitepaper è disponibile a questo indirizzo.

Man at work

Qualcuno avrà forse notato che sto sperimentando il formato "whitepaper" applicato al blog.
Si tratta di un esperimento con il quale intendo inaugurare una serie di whitepapers dedicati a casi di studio su progetti reali dei quali mi occupo.

Di questi whitepapers arriveranno al più presto anche le versioni PDF. Giusto il tempo di elaborare un'impaginazione carina.

Tecniche di "boxing" e "schermatura" per basi di dati SQL Server 2005

Nicola Orritos

Abstract

In contesti aziendali complessi ci si trova spesso di fronte a situazioni nelle quali i contenuti di una sola base di dati diventano una risorsa centrale e vitale per buona parte dell'infrastruttura IT dell'intero sistema (sia esso una grossa compagnia o un'organizzazione governativa).
Tale base di dati diventa un hub al quale devono poter accedere un gran numero di sistemi informativi implementati nelle più disparate tecnologie.

Inoltre queste stesse situazioni richiedono sempre più spesso che l'accesso a quegli stessi dati possa essere continuo e il più possibile performante (essendo presenti nell'infrastruttura alcuni sotto-sistemi che eseguono elaborazioni in real-time su di essi).
Una simile mole di richieste deve poter essere accuratamente gestita e controllata, onde evitare dispersioni dei dati, inconsistenze e utilizzi impropri degli stessi. Si ha cioè bisogno di uno strato di intermediazione tra le informazioni contenute nei database e chiunque ne faccia richiesta per qualsiasi motivo.

Questo documento intende esporre alcune delle possibili soluzioni che è possibile adottare per raggiungere tale scopo.
L'esposizione partirà da un'analisi dei vincoli imposti dal dover soddisfare tanti sistemi diversi e prenderà in considerazione un caso particolare nel quale alcune tecnologie pre-esistenti hanno posto dei seri vincoli al'operazione di ristrutturazione intrapresa.

1. La situazione di partenza

Il sistema sul quale si interverrà presenta una classica architettura "client-server", con un'unica base di dati che serve più agenti esterni, ciascuno dei quali ha la necessità di accedere a uno o più insiemi di dati, tutti ugualmente contenuti all'interno di un'unica istanza di un DBMS SqlServer 2005. Gli agenti esterni sono alcuni sistemi informativi appartenenti all'infrastruttura IT di un'unica azienda. Alcuni di loro sono realizzati con tecnologie "compatibili" con la base di dati, altri presentano invece dei problemi di compatibilità che hanno ristretto il numero delle soluzioni applicabili (i vincoli rappresentati da queste incompatibilità saranno analizzati nel paragrafo n.3 , "Requisiti e vincoli").

I dati contenuti nella base di dati (da ora indicata con l'acronimo "DB") devono essere costantemente disponibili ai molti agenti esterni e sarebbe desiderabile se gli accessi potessero avvenire con una certa velocità.
Queste necessità portano però con loro alcune conseguenze potenzialmente molto dannose: spesso e volentieri infatti si tende a varcare il confine che separa un accesso ubiquo ai dati da un loro utilizzo indiscriminato.
Tutto questo quando invece occorrerebbe mantenere i meccanismi e le politiche di accesso i più "semplici" ed efficienti possibili, schermando allo stesso tempo il DB da comportamenti dannosi quali possono essere la proliferazione indiscriminata di utenti, tabelle, viste e permessi.

Inoltre il problema sta non solo nei dati, ma investe anche gli schemi della base di dati e altri aspetti della struttura stessa dei dati: nel caso particolare qui analizzato, prima che ci si rendesse conto delle potenziali ricadute negative della cosa, molti cosiddetti "power-users" ritenuti meritevoli di un accesso poco limitato al sistema hanno dato vita a un variegato insieme di nuove tabelle, viste, Stored Procedure e utenti che costringevano la macchina ospitante il DB a un carico di lavoro a dir poco allarmante.

Un'ulteriore aggravante è costituita dal fatto che queste problematiche hanno un potenziale dannoso che tende a non poter essere controllato con sistemi tradizionali quali l'utilizzo degli "schema" e altre tipologie "classiche" di restrizione dei permessi.
Questo è in parte anche causato dal fatto che SQL Server 2005 utilizza un modello di sicurezza e di controllo degli accessi a dir poco complicato; ben più complicato di quanto potrebbe e dovrebbe essere per poter essere gestito agevolmente da un solo DBA.

2. Requisiti e vincoli

I vincoli ai quali dovrà sottostare la soluzione in grado di ovviare a tutti questi problemi sono molteplici e quasi tutti derivano dall'elevata mole di sistemi che accedono ai dati e dalle diverse modalità con cui ciascuno di essi lo fa.
Innanzitutto dovrà essere garantita un'implementazione semplice: saranno pertanto da evitare approcci che richiedono un eccessivo numero di passaggi da svolgere da parte dei sistemi esterni al DB centrale, così come architetture particolarmente cervellotiche o composte da troppi sistemi che debbano coordinarsi tra loro.

Una cosa importantissima è garantire l'univocità e la consistenza dei dati: nessuna replicazione o distribuzione degli stessi su più DB, a meno che la cosa non possa essere resa trasparente sia a livello di API esposte sia a livello "transazionale" (nel senso relazionale del "termine").

Un altro requisito fondamentale è poi cercare di rendere il passaggio dall'attuale situazione alla nuova il più "indolore" possibile per i sistemi coinvolti: questo significa mantenere il più possibile inalterate le modalità con cui ogni sistema accede al DB; a titolo esemplificativo valga la considerazione che se un sistema accede attualmente tramite una query T-SQLruntime SQL Server, sarebbe auspicabile che non debba in futuro adattarsi ad accedere tramite Web-Service, librerie dati o altre tecnologie diverse da quella già utilizzata.
Ciò è specialmente vero per quegli agenti esterni che basano il loro accesso su una particolare strategia tecnologica in quanto l'unica applicabile per interfacciarsi a SQL Server.

Nel caso reale seguito tutto ciò va a essere ulteriormente complicato dal fatto che dovrà essere garantito ad ogni costo l'uptime del DB, sia dalla soluzione stessa una volta che ne sia stato completato il deployment, sia durante tutta la fase di transizione ad essa.

Infine, il tutto dovrà essere realizzato parallelamente a un altro importantissimo progetto. Si tratta di un'architettura fisica che assicuri al DB centrale alcuni requisiti fondamentali che attualmente non sono ancora stati implementati, in particolare un failovering piuttosto robusto affidato a un cluster di più server (operazione attualmente già oggetto di un ulteriore studio che potrebbe anch'esso essere pubblicato).


3. Premesse a un'efficace soluzione del problema

Sia ben chiaro fin d'ora che non è possibile adempiere a quanto finora esposto senza una intensa collaborazione da parte di tutti i sistemi che accedono e sfruttano la base di dati centrale.
È cioè bene affermare sin da subito che un sistema che voglia accedere ai dati una volta che essi saranno "migrati" alla nuova soluzione non potrà limitarsi a semplici modifiche di alcune delle sue query.
La collaborazione non è infatti richiesta solo a ciascuno di questi sistemi in se, ma anche e soprattutto a coloro i quali di essi fanno utilizzo: saranno queste persone a dover fornire dettagliate descrizioni dei dati ai quali solitamente accedono (o vorrebbero accedere), dei legami tra i dati che intendono estrapolare dai DB, dei formati che si aspettano di ricevere dalle loro query e di tutti quei particolari che saranno poi necessari a fornire a tutti l'accesso più veloce e completo possibile.

Tali sistemi e le persone che ne gestiscono l'accesso al DB centrale saranno cioè parte integrante della soluzione; anzi, a voler essere più precisi, essi e la loro collaborazione saranno la fetta più consistente di essa.

Parte della documentazione che si intende ricavare da questa collaborazione potrà essere estrapolata dalle query e dai dati che già sono stati implementati sulla base di dati e per alcuni di essi sarà probabilmente sufficiente limitarsi a un simile approccio.
Per gli altri casi sarà invece utile (quando non indispensabile) se si potesse procedere alla compilazione da parte dei responsabili dei sistemi coinvolti nell'operazione di una sorta di "questionari" per l'identificazione dei requisiti che si credono necessari per un proficuo utilizzo del DB da parte del software di loro competenza.
Ancor meglio sarebbe organizzare una serie di briefing che possano adempiere a tale compito.


4. Descrizione di alcune delle soluzioni possibili

4.1 Schema generale della soluzione

L'idea generale che si intende perseguire è quella di effettuare un "boxing" dei dati in una struttura software o fisica (o entrambi), che consentano una "schermatura" dei dati stessi dalle influenze esterne.
Si tratta cioè di realizzare una membrana che faccia da mediatore nello scambi di dati occorrente tra il DB centrale e gli agenti esterni che adesso accedono.
Una simile membrana dovrà essere abbastanza intelligente e flessibile da consentire un accesso personalizzato per ogni agente esterno, cercando quanto più possibile di slegarsi dalla tecnologia con cui quest'ultimo si interfaccerà ai dati.
Volendo utilizzare un termine univoco e consistente per riferirsi a questa membrana si farà d'ora in poi uso del sostantivo "Sandbox".

Nonostante le soluzioni presentate differiscano a volte anche pesantemente l'una dall'altra, è possibile individuare tra di esse uno schema comune.
Questo elemento comune è appunto la Sandbox poc'anzi introdotta: un layer di intermediazione tra i dati e l'ecosistema esterno che sarà più o meno visibile alle applicazioni, a seconda dei requisiti di manipolazione dei dati di ciascuna di esse.
Questa "visibilità" discriminatoria ha principalmente la sua ragion d'essere nei requisiti precedentemente elencati: trasparenza e tendenza alla conservazione delle attuali modalità di interfacciamento dei sistemi esterni.

Comunque, quale che sia il modo in cui ciascun sistema esterno "vede" la base di dati, alcuni dei compiti della Sandbox sono stati fissati dal committente del progetto e hanno ovviamente imposto di considerare solo quelle soluzioni che permettevano un'aderenza totale ad essi.
Di seguito l'elenco di questi compiti:
  • supporto all'autenticazione per poter utilizzare i dati
  • logging estensivo delle attività svolte (soprattutto da "chi" esse sono state svolte, quando e in quanto tempo)
  • ottimizzazione spinta delle query eseguite (in modo da non gravare eccessivamente la/e macchina/e ospitante/i il DB)
  • report periodico (a mezzo e-mail) di eventuali malfunzionamenti e di un riassunto delle attività svolte

Un'ultima importantissima funzione integrata nella Sandbox sarà quella di fornire un'interfaccia di programmazione omogenea, ad alto livello e consistente, utilizzabile per creare librerie di accesso personalizzate al DB, secondo i protocolli imposti dalla Sandbox stessa.
Tale interfaccia sarà costituita da API la cui invocazione potrà avvenire sia attraverso script T-SQL sia via codice .NET (C# o VB.NET).

La realizzazione di quest'ultima funzionalità implica a sua volta la creazione di apposite "naming conventions" e di alcune librerie "helper" che aiutino gli utenti dei sistemi esterni a crearsi le proprie routines di accesso ai dati (o ad adattare quelle preesistenti). Tali librerie di supporto saranno parte integrante della Sandbox.

Le convenzioni e gli helpers manterranno essi stessi le modalità di accesso ai dati entro determinati "confini" decisi dagli amministratori del DB centrale.
Confini che dovranno poter essere "spostati" a run-time ricorrendo a un adeguato sistema di configurazione che dovrà perciò essere veloce oltre che omogeneo e di facile comprensione.

In questo strato di API confluirebbe infine tutto lo studio realizzato in collaborazione con i gestori dei vari sistemi esterni, portando cioè a frutto la collaborazione descritta nel paragrafo "3. Premesse a un'efficace soluzione del problema".

(Si noti come alcuni requisiti, ci si riferisce ai punti fissi imposti dal committente, non siano presenti nel paragrafo "2. Requisiti e vincoli" in quanto essi partecipano attivamente e profondamente alla definizione di un particolare schema nella soluzione in via di elaborazione)


4.2 Soluzione n.1: Strato di Web Services

Si tratta della prima e più semplice soluzione che è stata esaminata: semplice, elegante, riutilizzabile e ben supportata sia dalla tecnologia .NET, sia dalle librerie che già sono state scritte (in progetti precedenti) per il DB.

Essa presenta però un serio handicap: costringerebbe chi attualmente accede ai dati tramite query sottoposte direttamente al DB a riscrivere completamente la propria strategia di interfacciamento. Inoltre non tutti i linguaggi e le tecnologie hanno un supporto completo ed efficace agli WebServices.

Si notino comunque due cose che questa soluzione è in parte già stata implementata in almeno un caso particolare: infatti attualmente viene già garantito l'interfacciamento tramite Web Services tra il DB centrale e almeno altri due sistemi dell'ecosistema IT aziendale.
Una seconda nota va poi spesa per affermare come realizzare una soluzione mista (che comprenda quindi anche la tecnologia degli Web Services) sarebbe anch'essa una possibilità sulla quale val la pena contare (a questo proposito si veda il paragrafo "4.6 Pro e contro di un approccio misto").


4.3 Soluzione n.2: Stored Procedures in codice .NET

Piccola premessa: è stata dimostrato anche nel corso di passate collaborazioni con lo stesso committente che scrivere Stored Procedures per il DBMS SQL Server 2005 utilizzando la piattaforma .NET (e il linguaggio C# in particolare) è sufficientemente performante e "sicuro" (pur se non semplicissimo).

Partendo da questo presupposto è naturale ipotizzare uno scenario nel quale l'interfacciamento al DB centrale avvenga continuando ad accedere direttamente al DB, ma non andando più a operare sulle tabelle, bensì su Stored Procedures che ne astraggano dati e semantica, preferibilmente a un livello più alto.
All'atto pratico questo significa che quegli agenti esterni che già utilizzano SQL per accedere ai dati possono continuare a farlo in relativa tranquillità.

Un simile intervento dovrebbe contemplare adeguate convenzioni e verrebbe completato realizzando un modello di programmazione T-SQL e .NET per chi volesse realizzare nuove Stored Procedures: questo adempierebbe perfettamente a quanto descritto nella seconda metà del paragrafo "4.1 Schema generale della soluzione".

La realizzazione di questo modello implica la creazione di un tutorial indipendente dalla tecnologia (perché basato sul linguaggio SQL) e di appositi files di progetto, mirati invece per un utilizzo tramite Visual Studio .NET.
Il tutto guiderebbe all'estensione delle Stored Procedures di base, che saranno comunque già fornite dall'implementazione della soluzione stessa.

Come già detto, quest'approccio garantirebbe il mantenimento della modalità di accesso "diretta" al DB che già molti sistemi adottano: chi già accede in questo modo al DB si potrebbe infatti semplicemente limitare ad aggiornare le proprie query affinché puntino alle opportune Stored Procedures, piuttosto che alle tabelle (alle quali verrebbe tra l'altro precluso l'accesso, di fatto "schermando" l'universo tabellare dagli accessi esterni attraverso lo strato di Stored Procedures).

Inoltre scrivere le Stored Procedures in codice .NET significa che esse potranno svolgere compiti molto più evoluti di quelli permessi dal solo T-SQL: controllo degli accessi e logging fra tutti (adempiendo così ai requisiti elencati nei paragrafi precedenti).

Quasi superfluo aggiungere che combinare questa soluzione con quella che fa uso di Web Services è, oltre che possibile, anche una buona politica: i sistemi che non potessero realizzare librerie di accesso personalizzate in .NET o altri che avrebbero difficoltà ad utilizzare T-SQL potrebbero dialogare con uno o più Web Service appositi.


4.4 Soluzione n.3: Viste modificabili + Stored Procedures

In realtà quella descritta in questo paragrafo è nient'altro che una possibile estensione della precedente (Soluzione n.2): l'accesso non avverrebbe più tramite Stored Procedures, ma tramite "tabelle fittizie" che schermerebbero quelle reali dalla manipolazione diretta da parte dei sistemi esterni.
Le tabelle fittizie possono essere agevolmente realizzate combinando viste, triggers e Stored Procedures: si verrebbero così a creare delle viste modificabili che, reagirebbero a un tentativo di modifica scatenando un trigger che a sua volta invocherebbe apposite Stored Procedures. Si ricadrebbe insomma nella soluzione precedente, ma presentando agli agenti esterni uno schema dei dati ancora più vicino a quello attualmente da loro utilizzato.

Schema che sarebbe inoltre più "ricco" e completo, essendo le viste in questo senso più potenti e più semplici da capire delle Stored Procedures. Questo è un vantaggio che occorre però bilanciare con una maggiore complessità rispetto a quella del modello implementato dalla Soluzione n.2.
Ed è bene far notare come una maggiore complessità porti con se un maggior numero di errori e maggiori costi di manutenzione.


4.5 Soluzione n.4: Macchine "fantasma" + mirroring

Una strada che finora non è stata ancora considerata è quella di una Sandbox "fisica" (piuttosto che software). Per "Sandbox fisica" si intende dividere fisicamente i dati "puri" dalle informazioni che i sistemi esterni vorrebbero ricavare da essi.
Un'esigenza che nasce dal fatto che, nel contesto aziendale che ha richiesto la realizzazione di questo studio, era purtroppo diventata prassi comune realizzare tabelle per raccogliere e aggregare i dati originali in nuove forme; tabelle il cui proliferare indiscriminato genera inconsistenze, ridondanza, pesantezza nell'elaborazione e numerosi problemi di sicurezza.

Questa soluzione vorrebbe "confinare" queste grosse incongruenze a una macchina che non conserva i dati reali ma solo un loro "mirror" preso dal vero DB principale, il quale resterà invece nascosto (un "fantasma") a qualsiasi modifica.
Apposite Stored Procedures o una semplice procedura di mirroring provvederanno alla sincronizzazione delle sole tabelle presenti nel DB "fantasma" con solo i dati rilevanti della macchina esposta all'esterno.

Certo quest'approccio rappresenta senza dubbio un ulteriore livello di sicurezza, ma in se non risolve le problematiche che questo documento ha evidenziato (prima fra tutte l'eccessiva "libertà" con la quale alcuni agenti esterni possono modificare dati e schemi) e pertanto andrebbe adeguatamente integrato con una o più delle altre soluzioni elencate.


4.6 Pro e contro di un approccio misto

Unire alcune delle soluzioni su-esposte è un approccio sicuramente vincente sotto molti aspetti: risolve tutti i problemi e soddisfa tutti i requisiti, garantendo un'elevata flessibilità.
Allo stesso tempo, però, esso porta con se anche alcuni problemi nuovi e non trascurabili, dei quali la complessità è potenzialmente il più dannoso. Sarebbe pertanto opportuno tenere in considerazione l'aumento della complessità quando eventualmente si valuterà come unire le varie soluzioni.

A titolo di esempio: una soluzione come la n.3 ("Viste modificabili + Stored Procedures") è molto potente ma contempla un'architettura costituita di Viste, Triggers e Stored Procedures; ben si capisce che, rispetto alla soluzione n.2 ("Stored Procedures in codice .NET"), l'aumento della complessità è piuttosto rilevante e pericoloso.
Un pericolo che si può potenzialmente manifestare a diversi livelli: concettuale, prestazionale e in sede di manutenzione del sistema.


Conclusioni

Le soluzioni descritte in questo documento sono un primo passo che detterà il modello da seguire nella costruzione del vero e proprio "contenitore intelligente" per i dati del sistema commissionato. Il modello che si andrà a scegliere dovrà poi essere ulteriormente mediato e adattato a un gran numero di diverse esigenze che molti dei software che accedono al DB hanno: alla fine si avrà quasi certamente uno schema misto che include anche alcuni casi particolari (comunque in numero molto esiguo) e che fornirà si un'architettura di interfacciamento solida e uniforme ma anche (e soprattutto) flessibile e facilmente adattabile.