Treni senza macchinista (divagazioni sull’autodifesa di un database)

Da molti anni sbandiero a destra e sinistra (e anche al centro, visto il periodo elettorale è meglio usare la par-condicio) la mia idea: un database deve essere in grado di proteggersi da solo.

Che cosa significa?

Significa che, qualsiasi siano le mani che potranno toccarne i dati (siano applicativi, siano colleghi, …), il database dovrà essere sempre in grado di garantire la sua consistenza. In autonomia.

 

Questo si traduce in disegnare e modellare il db in modo tale che possa ricevere e gestire solo i dati corretti e nelle modalità in cui deve.

 

Prendo ad esempio (mi rendo conto che banalizzerò di molto la cosa) un recente fatto relativo ad un’azienda di trasporto ferroviario.

Un disservizio che ha provocato parecchi disagi, dovuti a non meglio precisati “problemi software”.

Prendo una delle segnalazioni riportate più volte dai media: " ... mentre ad altri (treni) mancava il macchinista, il controllore o entrambi".

 

In quei giorni ho letto e riletto la frase, molte volte, senza riuscire a capire come potesse essere “preparato” e messo sui binari un treno senza il suo macchinista o il suo controllore.

Ho provato ad ipotizzare le tabelle che gestiscono questi dati (treni, macchinisti, controllori, viaggi) con una modellazione come la seguente:

image

Mi è sembrato facile, quindi, utilizzare sia delle FOREIGN KEY che legassero in maniera certa “padre-figlio” (ad esempio: nei <viaggi> potrò avere solo <macchinisti> esistenti) ed il  constraint NOT NULL in modo tale che nessuno degli attributi della tabella [Viaggi] potesse essere vuoto (ad esempio: per ogni <viaggio> avrò sempre un <treno>, un <macchinista>, un <controllore> e una <data>).

Qualcosa come:

 CREATE TABLE Viaggi
( 
    idViaggio int PRIMARY KEY IDENTITY( 1 , 1 ) , 
    idTreno smallint FOREIGN KEY REFERENCES Treni( idTreno ) NOT NULL,
    idMacchinista smallint FOREIGN KEY REFERENCES Macchinisti( idMacchinista ) NOT NULL, 
    idControllore smallint FOREIGN KEY REFERENCES Controllori( idControllore ) NOT NULL, 
    dataViaggio date NOT NULL 
);
GO

 

Provando ad addentrarmi nelle problematiche di business mi sono anche immaginato (mi ripeto, sto sicuramente banalizzando le esigenze) altri requisiti, ad esempio:

  • un certo treno può esistere una sola volta in un giorno
  • un certo macchinista può lavorare su un solo treno in un giorno
  • ...

Anche qui, come sopra, mi è sembrato facile utilizzare un constraint UNIQUE in modo tale da rispondere in maniera certa alle mie necessità, ad esempio:

 ALTER TABLE viaggi
ADD CONSTRAINT uTreno UNIQUE( idTreno , dataViaggio );
GO

ALTER TABLE viaggi
ADD CONSTRAINT uMacchinista UNIQUE( idTreno, idMacchinista , dataViaggio );
GO

Con quanto ho sopra non ho certamente sviluppato il software di gestione della ferrovia, però, a prescindere da chi svilupperà il codice (e da come lo farà), ho già garantito che frasi come “ad altri (treni) mancava il macchinista, il controllore o entrambi” non potranno più essere scritte dai giornali.

 

Le scuole di pensiero su dove mettere regole di business (nel db? nell’applicativo? in entrambi? quanto mi “spingo”?) sono diverse e calate in scenari e necessità che possono, o devono, prediligere una o l’altra strada per vari motivi.

Senza voler imporre nulla a nessuno, però, ritengo che si possa sempre cercare di applicare la regola: “un database deve essere in grado di proteggersi da solo”.

Come sempre i commenti sono aperti.

Enjoy.