MATERIALE DIDATTICO IDONEITA CLASSE 5
I.T.I. INFORMATICA
INFORMATICA
TECNICHE DI TESTING
DISTINZIONE DI RUOLO DI LINGUAGGI
ARCHITETTURA DI VON NEUMANN
PROGETTAZIONE TOP-DOWN E BOTTOM-UP
PROGRAMMAZIONE FUNZIONALE
LINGUAGGI DI SPECIFICA
MODELLO CONCETTUALE DI UN SISTEMA INFORMATICO
SISTEMI PER LA GESTIONE DI BASI DI DATI (DBMS)
MODELLO RELAZIONALE
FILE HASH
TECNICHE DI TESTING
Nella Programmazione informatica, lo unit testing è una procedura usata
per verificare singole parti di un codice sorgente . Per unità si intende
genericamente la minima parte testabile di un codice sorgente: nella
programmazione procedurale un'unità può rappresentare un singolo
programma, funzione, procedura, etc.; nella Programmazione orientata
agli oggetti, la più piccola unità può essere il metodo.
Lo Unit Testing si articola in en:test case ciascuno dei quali dovrebbe
essere indipendente dagli altri. Lo Unit Testing viene normalmente
eseguito dagli sviluppatori, non da utenti final
Lo scopo dell'Unit testing è quello di verificare il corretto funzionamento
di parti di programma permettendo così una precoce individuazione dei
bug. Uno unit testing accurato può dare una prova certa se un pezzo di
codice funziona correttamente, con importanti vantaggi
Lo unit testing facilita la modifica del codice del modulo in momenti
successivi (en:refactoring) con la sicurezza che il modulo continuerà a
funzionare correttamente. Il procedimento consiste nello scrivere en:test
case per tutte le funzioni e i metodi, in modo che se una modifica produce
un fallimento del test, si possa facilmente individuare la modifica
responsabile. Lo unit testing semplifica l'integrazione di moduli diversi
perché limita i malfunzionamenti dovuti a problemi nella interazione tra i
moduli e non nei moduli stessi, rendendo i test di integrazione più
semplici. In generale il testing non riesce ad identificare tutti gli errori in
un programma e lo stesso vale per lo Unit Testing che, analizzando per
definizione le singole unità, non può identificare gli errori di
integrazione, problemi legati alla performance e altri problemi legati al
sistema in generale. Lo unit testing è più efficace se utilizzato in
congiunzione con altre tecniche di testing del software.
Come ogni forma di testing, anche lo Unit Testing non può individuare
l'assenza di errori ma può solo evidenziarne la presenz
Per ottenere gli sperati benefici dallo unit test, è richiesto un rigoroso
senso di disciplina durante tutto il processo di sviluppo. È essenziale
mantenere traccia non solo dei test che non stati sviluppati ed eseguiti, ma
anche di tutte le modifiche effettuate al codice funzionale dell'unità in
esame e di tutte le altre. L'uso di un sistema di controllo versione è
essenziale. Se una versione successiva di una unità fallisce un test che
aveva passato in precedenza, il sistema di controllo versione permette di
evidenziare le modifiche al codice intervenute nel frattempo.
Con la locuzione alpha testing, si indica una particolare fase del collaudo
del software, che si svolge internamente al gruppo degli sviluppatori ed
ha lo scopo di ricercare eventuali bug e malfunzionamenti.
Solitamente durante lo sviluppo di un software vengono realizzate diverse
versioni Alpha, in alcuni casi (soprattutto nel caso di software opensource) pubbliche, per introdurre nuove caratteristiche del software delle
quali è necessario controllare il funzionamento a fondo. Le versioni
Alpha sono quindi da considerare incomplete e mancanti di alcune
funzionalità e, spesso, instabili e perciò non adatte all'utente inesperto.
Al termine dell'Alpha testing si passa al beta testing dedicato alla
scoperta e soluzione dei bug, quindi si rilasciano una o più release
candidate, prima della versione finale.
il beta testing (o beta-verifica) è una fase di prova e collaudo di un
software non ancora pubblicato, con lo scopo di trovare eventuali errori
(bug). Questa operazione può essere svolta da professionisti pagati,
oppure, molto spesso, da semplici amatori, chiamati beta tester. La loro
importanza è legata, oltre al test dei sistemi operativi, anche ai programmi
minori poiché tendono a comportasi diversamente in base all'hardware su
cui girano, per cui conviene avere la possibilità di provarli su più
hardware differenti. Alla fine del beta testing, il programma è considerato
completo e distribuibile. Si parlerà quindi, a questo punto, di versione
build. Se si tratta di software commerciale, non è detto che i beta tester
ricevano una copia gratuita del software.
DISTINZIONE E RUOLO DEI LINGUAGGI
L'Elaborazione del linguaggio naturale, detta anche NLP (dall'inglese
Natural Language Processing), è il processo di estrazione di
informazioni semantiche da espressioni del linguaggio umano o naturale,
scritte o parlate, tramite l'elaborazione di un calcolatore elettronico.
Questo processo è reso particolarmente difficile e complesso a causa
delle caratteristiche intrinseche di ambiguità del linguaggio umano. Per
questo motivo il processo di elaborazione viene suddiviso in fasi diverse,
tuttavia simili a quelle che si possono incontrare nel processo di
elaborazione di un linguaggio di programmazione:
•
analisi lessicale: scomposizione di un'espressione linguistica in
token (in questo caso le parole)
•
analisi grammaticale: associazione delle parti del discorso a
ciascuna parola nel testo
•
analisi sintattica: arrangiamento dei token in una struttura sintattica
(ad albero: parse tree)
•
analisi semantica: assegnazione di un significato (semantica) alla
struttura sintattica e, di conseguenza, all'espressione linguistica
In informatica, un linguaggio di programmazione è un linguaggio
formale, dotato di un lessico, una sintassi e una semantica ben definite,
utilizzabile per il controllo del comportamento di una macchina formale,
o di una implementazione di essa (tipicamente, un computer).
Tutti i linguaggi di programmazione esistenti possiedono (almeno) questi
due concetti chiave:
•
Variabile: un dato o un insieme di dati, noti o ignoti, già
memorizzati o da memorizzare; ad una variabile corrisponde
sempre, da qualche parte, un certo numero (fisso o variabile) di
locazioni di memoria che vengono allocate, cioè riservate, per
contenere i dati stessi. Molti linguaggi inoltre attribuiscono alle
variabili un tipo, con differenti proprietà (stringhe di testo, numeri,
liste, atomi ecc.).
•
Istruzione: un comando, una funzione, oppure una regola
descrittiva: anche il concetto di istruzione è molto variabile fra i
vari linguaggi. A prescindere dal particolare linguaggio però, ogni
volta che un'istruzione viene eseguita, lo stato interno del
calcolatore (che sia lo stato reale della macchina oppure un
ambiente virtuale, teorico, creato dal linguaggio) cambia.
Alcuni concetti sono poi presenti nella gran parte dei linguaggi:
•
Espressione: una combinazione di variabili e costanti, unite da
operatori; le espressioni sono state introdotte inizialmente per
rappresentare le espressioni matematiche, ma in seguito la loro
funzionalità si è estesa. Una espressione viene valutata per
produrre un valore, e la sua valutazione può produrre "effetti
collaterali" sul sistema e/o sugli oggetti che vi partecipano.
•
Strutture di controllo, che permettono di governare il flusso
dell'esecuzione del programma, alterandolo in base al risultato di
una espressione (che può ridursi al contenuto di una variabile, o
essere anche molto complessa).
•
Sottoprogramma: un blocco di codice che può essere richiamato da
qualsiasi altro punto del programma.
•
Strutture dati, meccanismi che permettono di organizzare e gestire
dati complessi.
Programmare in un dato linguaggio di programmazione significa
generalmente scrivere uno o più semplici file di testo ASCII, chiamato
codice sorgente. I font, i colori e in generale l'aspetto grafico sono
irrilevanti ai fini della programmazione in sé: per questo i programmatori
non usano programmi di videoscrittura ma degli editor di testo (come
emacs e brief) che invece offrono funzioni avanzate di trattamento testi
(espressioni regolari, sostituzioni condizionali e ricerche su file multipli,
possibilità di richiamare strumenti esterni ecc). Se un dato editor è in
grado di lavorare a stretto contatto con gli altri strumenti di lavoro
(compilatore, linker, interprete ecc.: vedi più avanti) allora più che di
semplice editor si parla di IDE o ambiente di sviluppo integrato. Va
notato che alcuni linguaggi di programmazione recenti consentono anche
una forma mista di programmazione, in cui alla stesura di codice sorgente
ASCII si associano anche operazioni di programmazione visuale,
attraverso le quali il programmatore descrive alcuni aspetti del
programma disegnando a video attraverso il mouse; un'applicazione
tipica di quest'ultima forma di programmazione è il disegno interattivo
della GUI del programma (finestre, menù, e così via).
Il codice sorgente, contenente le istruzioni da eseguire e (spesso) alcuni
dati noti e costanti, può essere poi eseguito passandolo ad un interprete
che eseguirà le istruzioni in esso contenute, il che è la prassi normale per i
linguaggi di scripting; oppure può venire compilato, cioè tradotto in
istruzioni di linguaggio macchina da un programma compilatore: il
risultato è un file binario 'eseguibile' (codice eseguibile) che non ha
bisogno di altri programmi per andare in esecuzione, ed è anche molto
più veloce di un programma interpretato.
In passato, la compilazione è stata la norma per tutti i linguaggi di
programmazione di uso generale; attualmente vi sono numerosi linguaggi
interpretati e di uso generale, come il linguaggio Java o quelli della
piattaforma .NET, che applicano un approccio ibrido fra le due soluzioni,
utilizzando un compilatore per produrre del codice in un linguaggio
intermedio (detto bytecode) che viene successivamente interpretato. La
differenza di prestazioni tra i linguaggi interpretati e quelli compilati è
stata ridotta con tecniche di compilazione just-in-time, sebbene si
continui ad utilizzare i linguaggi compilati (se non addirittura l'assembly)
per le applicazioni che richiedono le massime prestazioni possibili.
La compilazione è il processo per cui il programma, scritto in un
linguaggio di programmazione ad alto livello, viene tradotto in un codice
eseguibile per mezzo di un altro programma detto appunto compilatore.
La compilazione offre numerosi vantaggi, primo fra tutti il fatto di
ottenere eseguibili velocissimi nella fase di run (esecuzione) adattando
vari parametri di questa fase all'hardware a disposizione; ma ha lo
svantaggio principale nel fatto che è necessario compilare un eseguibile
diverso per ogni sistema operativo o hardware sul quale si desidera
rendere disponibile l'esecuzione.
ARCHITETTURA DI VON NEUMANN
Con l'espressione architettura di von Neumann (o macchina di von
Neumann) ci si riferisce a uno schema di progettazione di calcolatori
elettronici che prende nome dal matematico John von Neumann e che fu
sviluppato per il sistema IAS machine e dell'Institute for Advanced
Study.
Lo schema si basa su cinque componenti fondamentali:
1. CPU o unità di lavoro che si divide a sua volta in
1. Unità operativa, nella quale uno dei sottosistemi più rilevanti
è l'ALU (Arithmetic Logic Unit)
2. Unità di controllo
2. Unità di memoria, intesa come memoria di lavoro o memoria
principale (RAM, Random Access Memory)
3. Unità di input, tramite la quale i dati vengono inseriti nel
calcolatore per essere elaborati
4. Unità di output, necessaria affinché i dati elaborati possano essere
restituiti all'operatore
5. Bus, un canale che collega tutti i componenti fra loro
All'interno dell'ALU è presente un registro detto accumulatore, che fa da
buffer tra input e output grazie a una speciale istruzione che carica una
parola dalla memoria all'accumulatore e viceversa.
È importante sottolineare che tale architettura, a differenza di altre, si
distingue per la caratteristica di immagazzinare all'interno dell'unità di
memoria, sia i dati dei programmi in esecuzione che il codice di questi
ultimi.
Bisogna comunque precisare che questa è una schematizzazione molto
sintetica, sebbene molto potente: basti pensare che i moderni computer di
uso comune sono progettati secondo l'architettura Von Neumann.
Inoltre, quando si parla di unità di memoria si intende la memoria
principale, mentre le memorie di massa sono considerate dispositivi di
I/O.
Il motivo di ciò è innanzitutto storico, in quanto negli anni Quaranta,
epoca a cui risale questa architettura, la tecnologia non lasciava neanche
presupporre dispositivi come hard disk, CD-ROM, DVD-ROM o anche
solo nastri magnetici, ma anche tecnico, se si considera che in effetti i
dati da elaborare devono comunque essere caricati in RAM, siano essi
provenienti da tastiera o da hard-disk.
PROGETTAZIONE TOP-DOWN E BOTTOM-UP
I modelli top-down e bottom-up (ing. dall'alto verso il basso e dal basso
verso
l'alto,
rispettivamente)
dell'informazione
e
di
sono
gestione
strategie
delle
di
conoscenze,
elaborazione
riguardanti
principalmente il software e, per estensione, altre teorie umanistiche e
teorie dei sistemi. In linea generale, esse sono metodologie adoperate per
analizzare situazioni problematiche e costruire ipotesi adeguate alla loro
soluzione: il concetto di situazione problematica è riconducibile ad ambiti
tra i più vari come ad esempio la elaborazione di un programma
informatico, la risoluzione di un problema geometrico ovvero
matematico, la elaborazione di un testo, la risoluzione di un problema
pratico/operativo.
Nel modello top-down è formulata una visione generale del sistema senza
scendere nel dettaglio di alcuna delle sue parti. Ogni parte del sistema è
successivamente
rifinita
(decomposizione,
specificazione o identificazione)
[1]
specializzazione
e
aggiungendo maggiori dettagli dalla
progettazione. Ogni nuova parte così ottenuta può quindi essere
nuovamente rifinita, specificando ulteriori dettagli finché la specifica
completa è sufficientemente dettagliata da validare il modello. Il modello
top-down è spesso progettato con l'ausilio di scatole nere che
semplificano il riempimento ma non consentono di capirne il meccanismo
elementare.
In contrasto con il modello top-down c'è la progettazione bottom-up,
nella quale parti individuali del sistema sono specificate in dettaglio.
Queste parti vengono poi connesse tra loro in modo da formare
componenti più grandi, che vengono a loro volta interconnessi fino a
realizzare un sistema completo. Le strategie basate sul flusso informativo
bottom-up sembrano potenzialmente necessarie e sufficienti dato che
sono basate sulla conoscenza di tutte le variabili che possono
condizionare gli elementi del sistema.
Il top down richiama l'immagine di una piramide con la cima (top) in alto
e la base (down) posta in posizione orizzontale; la caratterizzazione
dinamica del metodo prevede di partire dal top e scendere verso il down.
Top, termine molto usato nel linguaggio contemporaneo (top ten, top
model, ecc.), può essere efficacemente tradotto in obiettivo inteso come
obiettivo da raggiungere per risolvere una situazione problematica; down
è
riconducibile
alla
strategia
necessaria
a
conseguire
il
fine
predeterminato.
Il top down parte dall'obiettivo e da esso fa scaturire la strategia
direttamente adatta a determinare l'obiettivo stesso, quindi valorizza il
perché e da esso fa dipendere il come, ovvero la strategia; individua,
quindi, le risorse necessarie, precisa quelle disponibili e identifica quelle
mancanti, propone successivamente ogni risorsa mancante come subobiettivo ovvero come sotto-problema in cui ciascun sub-obiettivo
richiede una sub-strategia ad esso correlata.
Il top down struttura e sistematizza la riflessione, motiva ogni passaggio
in modo logico e ripulisce il metodo di lavoro da tentativi casuali,
intreccia strettamente analisi ed elaborazione, dà alla strategia
complessiva un carattere di eleganza sostanziale e formale che si
estrinseca come trasparenza e sistematicità.
È soprattutto adatto, ma non solo, a situazioni complesse, inedite, di
differenti tipologie.
Il bottom up richiama invece un'immagine raffigurante una freccia in cui
la coda è il bottom (la parte bassa) mentre up è la punta: dal punto di vista
dinamico si parte dal bottom e si procede verso up.
Il bottom up prende corpo dal punto di partenza (bottom) ovvero dalla
situazione iniziale; considera l'obiettivo finale, induce a costruire un
percorso sequenziale organizzato in passaggi successivi in cui
l'ancoraggio tra traguardi intermedi e obiettivo finale è ricercato con
metodo generalmente improntato a tentativo ed errore quindi di tipo
casuale, nei casi migliori intuitivo.
È per lo più adatto a situazioni problematiche lineari, semplici, delle quali
la dinamica è generalmente nota.
Nel processo di sviluppo software, gli approcci top-down e bottom-up
giocano un ruolo fondamentale. L'approccio top-down enfatizza la
pianificazione ed una completa comprensione del sistema. È ovvio che
nessuna codifica può iniziare finché non si è raggiunto almeno un
sufficiente livello di dettaglio nella progettazione di una parte significante
del sistema. Questo, comunque, ritarda la fase di test delle ultime unità
funzionali di un sistema finché una parte significativa della progettazione
non è stata completata. L'approccio bottom-up enfatizza la codifica e la
fase di test precoce, che può iniziare appena il primo modulo è stato
specificato. Questo approccio, comunque, induce il rischio che i moduli
possano essere codificati senza avere una chiara idea di come dovranno
essere connessi ad altre parti del sistema, e quel tipo di link potrebbe non
essere facile. La riusabilità del codice è uno dei principali benefici
dell'approccio bottom-up
La programmazione top-down è uno stile di programmazione,
fondamento dei tradizionali linguaggi procedurali, nel quale la
progettazione inizia specificando parti complesse e suddividendole
successivamente in parti più piccole. Eventualmente, i componenti sono
specificati quanto basta per la codifica ed il programma viene anche
scritto. Questo è l'esatto opposto della programmazione bottom-up che è
comune nei linguaggi orientati agli oggetti come C++ o Java. La tecnica
per la scrittura di un programma mediante l'utilizzo dei metodi top-down
indica di scrivere una procedura principale che indica dei nomi per le
principali funzioni di cui avrà bisogno. In seguito, il gruppo di
programmazione esaminerà i requisiti di ognuna di queste funzioni ed il
processo verrà ripetuto. Queste sotto-procedure a comparto eseguiranno
eventualmente azioni così semplici che porteranno ad una codifica
semplice e concisa. Quando tutte le varie sotto-procedure sono state
codificate, il programma è realizzato.
PROGRAMMAZIONE FUNZIONALE
in informatica la programmazione funzionale è un paradigma di
programmazione in cui il flusso di esecuzione del programma assume la
forma di una serie di valutazioni di funzioni matematiche. Solitamente
questo approccio viene usato maggiormente in ambiti accademici
piuttosto che industriali. Il punto di forza principale di questo paradigma
è la mancanza di effetti collaterali (side-effect) delle funzioni, il che
comporta una più facile verifica della correttezza e della mancanza di bug
del programma e la possibilità di una maggiore ottimizzazione dello
stesso. Un uso particolare del paradigma, per l'ottimizzazione dei
programmi, è quello di trasformare gli stessi per utilizzarli nella
programmazione parallela.
La programmazione funzionale pone maggior accento sulla definizione di
funzioni, rispetto ai paradigmi procedurali e imperativi, che invece
prediligono la specifica di una sequenza di comandi da eseguire. In questi
ultimi, i valori vengono calcolati cambiando lo stato del programma
attraverso delle assegnazioni; un programma funzionale, invece, è
immutabile: i valori non vengono trovati cambiando lo stato del
programma, ma costruendo nuovi stati a partire dai precedenti.
L'esempio più vecchio di linguaggio funzionale è il Lisp, anche se né il
LISP originale né i Lisp moderni, come il Common Lisp, sono puramente
funzionali. Le varianti del Lisp includono il Logo, lo Scheme, Dylan e
Clojure. Esempi di linguaggi funzionali moderni sono l'Haskell e i
linguaggi della famiglia ML, quali ML e OCaml. Un altro linguaggio
derivato da ML è F#, sviluppato da Microsoft all'interno del framework
.NET.
Altri sono l'Erlang, Mathematica, il Clean e Miranda.
Altri linguaggi, come per esempio Ruby, Python, Perl e TCL, possono
essere usati in stile funzionale, dato che hanno funzioni di ordine
superiore e altre astrazioni utili.
Oggi si sta cercando anche di sviluppare linguaggi di programmazione
funzionali quantistici, cioè che possano esprimere algoritmi quantistici.
Alcuni esempi sono il linguaggio di Peter Selinger
ed il linguaggio Haskell-like QML
LINGUAGGI DI SPECIFICA
Il termine specifica, nell’ingegneria del software, viene usato in diversi
contesti con significati diversi. In genere si può definire come un accordo
tra un produttore di servizi ed un utente. A seconda del contesto il
produttore e l’utente saranno diversi.
Si avrà una specifica dei requisiti tra sviluppatore e committente o utente
finale, una specifica di progetto tra progettista e implementatore e una
specifica di modulo tra i programmatori che hanno prodotto il modulo e
programmatore che lo integra.
La Specifica dei Requisiti è usata per
•
Definire le necessità dell’utente
•
Definire le caratteristiche del sistema implementato
•
Comprendere il sistema nelle attività di manutenzione
La fase di specifica dei requisiti è molto critica, se i requisiti non
prendono in esame alcuni aspetti il progetto rischierebbe degli inutili
ritardi e inevitabili manutenzioni. Per questo motivo è necessario
effettuare
la
validazione
approvazione dell’utente.
della
specifica,
ossia
sottoporla
alla
Non esiste un unico modo di scrivere una specifica
•
Dipende dalla tipologia del sistema
•
Dipende dal livello di formalità
•
Dipende dallo stile di specifica che si vuole adottare
Una specifica deve essere
•
Chiara, precisa e comprensibile
•
Coerente
•
Completa
L’uso del linguaggio naturale (italiano, inglese,...) fa sì che spesso le
qualità di chiarezza, precisione e comprensibilità non siano presenti.
Tipicamente c’è la tendenza ad essere imprecisi. L’uso di tecniche
formali consente di scoprire le ambiguità. Ci sono formule diverse che
definiscono lo stesso comportamento informale.
La coerenza è l’assenza di contraddizioni. Più il sistema è complesso più
è facile che vi siano delle inconsistenze. L’uso di tecniche formali può
permettere l’individuazione di inconsistenze.
La completezza riguarda la presenza di tutte le informazioni necessarie ad
una corretta comprensione. Vi sono due tipi di completezza:
•
Interna
•
Rispetto ai requisiti
Una specifica è internamente completa se definisce tutti i concetti di cui
fa uso e si può ottenere mediante l’uso di glossari. La completezza
rispetto ai requisiti richiede che tutti gli aspetti siano definiti. Se il
sistema è complesso. Un approccio incrementale può essere utile.
Le specifiche possono essere poste in maniera formale o in maniera
informale. Le specifiche informali fanno uso di linguaggio naturale per
descrivere i requisiti. Possono essere utilizzati diagrammi e tabelle per
aumentare le informazioni. La sintassi e la semantica non sono
formalmente definite.
Le specifiche formali usano linguaggi che hanno sintassi e semantica
definite in modo formale e sono usate principalmente per sistemi safetycritical. Consentono animazione, simulazione e verifica di proprietà.
Esistono anche le specifiche semiformali:
•
Fanno uso di sintassi formalmente definita, ma la semantica è
informale
•
Molto spesso sono linguaggi grafici
La seconda distinzione è tra specifiche operazionali e specifiche
descrittive. La prima descrive il sistema desiderato specificando il
comportamento desiderato, fornendo di solito un modello del sistema, le
seconde esprimono le proprietà desiderate in modo puramente
dichiarativo.
MODELLO CONCETTUALE
Un modello concettuale rappresenta concetti (entità e relationi tra le
entità, a differenza di un modello mentale che descrive idee di un certo
dominio del problema.
La modellazione o progettazione concettuale è una tecnica molto nota di
progettazione dati, assieme alla progettazione logica e alla progettazione
fisica.
Il modello concettuale deve essere per definizione indipendente dai
dettagli dell'implementazione, come la concorrenza o la memorizzazione
deidati.
Lo scopo del modello concettuale è esprimere il significato di termini e
concetti usati dagli esperti del dominio per discutere il problema, e a
trovare le giuste relazioni tra concetti differenti. Questo modello è anche
chiamatomodellosemantico.
Il modello concettuale cerca di chiarire il significato di vari termini
spesso ambigui, e assicura che non ci siano problemi con una differente
interpretazione di termini e concetti. Questo perché, tali interpretazioni
possono portare errori nel progetto software basato su tale interpretazione
dei concetti. Una volta che i concetti del dominio sono stati modellati, il
modello diventa una base stabile per lo sviluppo successivo
dell'applicazione nel dominio. I concetti del modello concettuale possono
essere usati come base di una progettazione orientata agli oggetti e
implementati in un programma, come le classi di un linguaggio orientato
agli oggetti. La realizzazione di modelli concettuali di domini diversi
possono essere combinati tra di loro a formare una piattaforma coerente.
Un modello concettuale può essere descritto usando varie notazioni,
come UML o OMT per la progettazione a oggetti, o IE o IDEF1X per il
Modello
entità-relazione.
Nella notazione UML, il modello concettuale è spesso descritto con un
class diagram nel quale le classi rappresentano concetti, le associazioni
rappresentano relazioni tra i concetti e i role type di un'associazione
rappresentano i "role types" assunti dalle istanze dei concetti nelle varie
situazioni. Nella notazione ER, il modello concettuale è descritto con un
diagramma ERnel quale le entità rappresentano i concetti, cardinalità and
opzionalità rappresentano le relazioni tra i concetti.
SISTEMI PER LA GESTIONE DI BASI DI DATI
In informatica, il termine database, banca dati, base di dati (soprattutto in
testi accademici) o anche base dati, indica un archivio strutturato in modo
tale da consentire la gestione dei dati stessi (l'inserimento, la ricerca, la
cancellazione ed il loro aggiornamento) da parte di applicazioni software.
Il database è un insieme di informazioni, di dati che vengono suddivisi
per argomenti in ordine logico (tabelle) e poi tali argomenti vengono
suddivisi per categorie (campi).
Informalmente e impropriamente, la parola "database" viene spesso usata
come abbreviazione dell'espressione Database Management System
(DBMS), che si riferisce a una vasta categoria di sistemi software che
consentono la creazione e la manipolazione efficiente di database.
La base di dati, oltre ai dati veri e propri, deve contenere anche le
informazioni sulle loro rappresentazioni e sulle relazioni che li legano.
Spesso, ma non necessariamente, una base dati contiene le seguenti
informazioni:
•
Strutture dati che velocizzano le operazioni frequenti, tipicamente
a spese di operazioni meno frequenti.
•
Collegamenti con dati esterni, cioè riferimenti a file locali o remoti
non facenti parte del database.
•
Informazioni di sicurezza, che autorizzano solo alcuni profili
utente ad eseguire alcune operazioni su alcuni tipi di dati.
•
Programmi che vengono eseguiti, automaticamente o su richiesta
di utenti autorizzati, per eseguire elaborazioni sui dati. Un tipico
automatismo consiste nell'eseguire un programma ogni volta che
viene modificato un dato di un certo tipo.
In un sistema informatico, una base di dati può essere manipolata
direttamente dai programmi applicativi, interfacciandosi direttamente con
il sistema operativo. Tale strategia era quella adottata universalmente fino
agli anni sessanta, ed è tuttora impiegata quando i dati hanno una struttura
molto semplice, o quando sono elaborati da un solo programma
applicativo.
A partire dalla fine degli anni Sessanta, tuttavia, per gestire basi di dati
complesse condivise da più applicazioni si sono utilizzati appositi sistemi
software, detti sistemi per la gestione di basi di dati (in inglese "Database
Management System" o "DBMS"). Uno dei vantaggi di questi sistemi è la
possibilità di non agire direttamente sui dati, ma di vederne una
rappresentazione concettuale.
La ricerca nel campo delle basi di dati studia le seguenti problematiche:
•
Progettazione di basi di dati.
•
Progettazione e implementazione di DBMS.
•
Interpretazione (o analisi) di dati contenuti in database.
Le basi di dati spesso fanno uso di tecnologie derivate da altre branche
dell'informatica. È usuale utilizzare tecniche derivate dall'intelligenza
artificiale, come ad esempio il data mining, per cercare di estrarre
relazioni o più in generale informazioni presenti nelle banche dati ma non
immediatamente visibili.
È possibile distinguere i linguaggi per basi di dati secondo il loro utilizzo:
•
Data Definition Language (DDL) - consente di definire la struttura
della base di dati e le autorizzazioni per l'accesso.
•
Device Media Control Language (DMCL) - permette alla struttura
fisica del database di far riferimento alle particolari unità di
memoria di massa utilizzate dal sistema.
•
Data Manipulation Language (DML) - consente di interrogare e
aggiornare le istanze della base di dati.
•
Data Control Language (DCL) - permette la gestione dell'accesso
al
database
con
relative
restrizioni
di
operazioni
come
aggiornamento, selezione e cancellazione.
•
Query language (QL) - permette di interrogare il database al fine di
ritrovare i dati relativi alla chiave di ricerca impostata dall'utente.
Inoltre è possibile suddividere i linguaggi come:
•
Linguaggi testuali interattivi, come l'SQL, di cui sono stati
pubblicati diversi standard, che attualmente è il linguaggio più
utilizzato.
•
Linguaggi
testuali
interattivi
immersi
in
linguaggi
di
in
linguaggi
di
programmazione comuni, quali C, Basic ecc.
•
Linguaggi
testuali
interattivi
immersi
programmazione proprietari.
•
Linguaggi grafici e user-friendly, come QBE (Query By Example),
che possono essere utilizzati anche dai meno esperti.
MODELLO RELAZIONALE
Il modello relazionale è un modello logico di rappresentazione dei dati
implementato su sistemi di gestione di basi di dati (DBMS), detti perciò
sistemi di gestione di basi di dati relazionali (RDBMS). Esso si basa
sull'algebra relazionale e sulla teoria degli insiemi ed è strutturato attorno
al concetto di relazione (detta anche tabella).
Venne proposto da Edgar F. Codd nel 1970 per semplificare la scrittura di
interrogazioni sui database e per favorire l’indipendenza dei dati; venne
reso disponibile come modello logico in DBMS reali nel 1981.
Oggi è uno dei modelli logici più utilizzati, implementato su moltissimi
DBMS sia commerciali che open source.
L'assunto fondamentale del modello relazionale è che tutti i dati sono
rappresentati come relazioni; i dati sono manipolati con gli operatori
dell'algebra relazionale.
Il modello relazionale consente al progettista di database di creare una
rappresentazione consistente e logica dell'informazione. La consistenza
viene ottenuta inserendo nel progetto del database appropriati vincoli,
normalmente chiamati schema logico. La teoria comprende anche un
processo di normalizzazione in base al quale viene selezionato tra le
diverse alternative lo schema maggiormente "desiderabile". Il piano di
accesso e altri dettagli operativi vengono gestiti dal motore del DBMS e
non dovrebbero trovare spazio nello schema logico: questo è in contrasto
con la pratica corrente in molti DBMS di ottenere miglioramenti delle
prestazioni attraverso modifiche dello schema logico.
La struttura base del modello relazionale è il dominio o tipo di dato,
definito come l'insieme dei valori che può assumere un determinato
attributo. Una tupla è un insieme non ordinato di valori degli attributi. Un
attributo è una coppia ordinata di "nome di attributo" e "nome di tipo",
mentre un valore di attributo è un valore specifico valido per quel tipo di
dato.
Una relazione consiste di una testata e di un corpo, dove la testata è un
insieme di attributi e il corpo è un insieme di n tuple. La testata di una
relazione è anche la testata di ciascuna delle sue tuple.
La tabella è la rappresentazione grafica normalmente accettata per
rappresentare la relazione.
Il principio base del modello relazionale è che tutte le informazioni siano
rappresentate da valori inseriti in relazioni (tabelle); dunque un database
relazionale è un insieme di relazioni contenenti valori e il risultato di
qualunque interrogazione (o manipolazione) dei dati può essere
rappresentato anch'esso da relazioni (tabelle).
Il tipo di dato come viene usato nei database relazionali può essere un
insieme di numeri interi, un insieme di caratteri alfanumerici, l'insieme
delle date, i valori booleani vero e falso, e così via. I corrispondenti
"nomi di tipo" per saranno le stringhe "int", "char", "date", "boolean", etc.
Da sottolineare che da una parte la teoria relazionale non definisce quali
tipi vadano supportati, e dall'altra molti sistemi garantiscono la possibilità
di definire tipi di dati definiti dall'utente, in aggiunta a quelli "standard"
forniti dal sistema.
Attributo è il termine usato nella teoria per ciò che normalmente si
definisce come colonna. Allo stesso modo tabella è normalmente usato al
posto del termine teorico relazione. La struttura di una tabella è
specificata come una lista di colonne, ciascuna delle quali ha un nome
univoco e un dominio, un insieme cioè di valori accettati. Un valore di
attributo è il valore di una cella identificata da una specifica coppia riga colonna, come ad esempio "Mario Rossi" o "2006".
Una tupla è praticamente la stessa cosa di una riga.
Una relazione è la definizione di una tabella (cioè un insieme di colonne)
insieme ai dati che vi compaiono. La definizione della tabella è la testata
e i dati che vi appaiono sono il corpo, un insieme di righe.
Il modello relazionale risponde al requisito dell'indipendenza dei dati e
prevede una distinzione tra il livello fisico e il livello logico: questa
capacità di astrazione ha fatto la sua fortuna nel mondo della gestione
dati.
Prima dell'avvento del modello relazionale, i DBMS utilizzavano altri
due modelli logici di database: il modello gerarchico e il modello
reticolare. Sebbene oggi la gran parte dei DBMS aderiscano (o dicano di
aderire: v. le 12 regole di Codd) al modello relazionale, in alcuni centri
elettronici sono ancora utilizzati DBMS gerarchici o reticolari,
specialmente in casi in cui la migrazione avrebbe costi proibitivi.
Secondo alcuni autori il modello relazionale potrebbe in futuro cedere il
passo a un modello object oriented, ma da una parte i DBMS objectoriented (OODBMS) stentano ad affermarsi, dall'altra i migliori DBMS
relazionali stanno rilasciando funzionalità object-oriented, come la
possibilità di definire tipi di dato utente.
FILE HASH
Nel linguaggio matematico e informatico, la funzione hash è una
funzione non iniettiva che mappa una stringa di lunghezza arbitraria in
una stringa di lunghezza predefinita. Esistono numerosi algoritmi che
realizzano funzioni hash con particolari proprietà che dipendono
dall'applicazione.
Nelle applicazioni crittografiche si chiede, per esempio, che la funzione
hash abbia le seguenti proprietà:
•
resistenza alla preimmagine: sia computazionalmente intrattabile la
ricerca di una stringa in input che dia un hash uguale a un dato
hash;
•
resistenza alla seconda preimmagine: sia computazionalmente
intrattabile la ricerca di una stringa in input che dia un hash uguale
a quello di una data stringa;
•
resistenza alle collisioni: sia computazionalmente intrattabile la
ricerca di una coppia di stringhe in input che diano lo stesso hash.
Nelle applicazioni di basi di dati la funzione hash è usata per realizzare
una particolare struttura dati chiamata hash table. In questa applicazione
non occorrono proprietà crittografiche e generalmente l'unica proprietà
richiesta è che non ci siano hash più probabili di altri
È possibile utilizzare le funzioni di hash per creare una hash table:
struttura dati molto efficiente per immagazzinare generici dati associati
ad una chiave. Questo genere di struttura dati viene spesso utilizzata nei
Database per generare gli indici dato che permette di realizzare funzioni
di ricerca che individuano gli elementi in un tempo costante, indipendente
(almeno in teoria) dal numero di elementi presenti nell'indice.
L'uso delle funzioni hash per trovare errori nelle trasmissioni è molto
comune. La funzione hash viene calcolata a partire dai dati dal
trasmettitore e il suo valore è inviato insieme ai dati. Il ricevitore calcola
di nuovo la funzione hash, e se i valori hash non corrispondono, significa
che è avvenuto un errore durante la trasmissione. Questo metodo è
chiamato controllo ridondante.