SOFTWARE
Ingegneria del software. - Nel contesto di questa voce, il termine software verrà usato in un'accezione ampia, che comprende sia il prodotto, cioè l'insieme dei programmi, della relativa documentazione e delle procedure operative mediante le quali gli elaboratori elettronici possono svolgere le funzioni che sono state loro richieste, sia il processo di produzione, attraverso il quale, in una successione di fasi e di attività, il prodotto viene realizzato a partire dai requisiti iniziali e mantenuto operativo. L'ingegneria del s. può pertanto essere definita come la scienza e l'arte di realizzare prodotti s. che soddisfino certi prestabiliti obiettivi di qualità mantenendosi entro costi e tempi accettabili, e cioè mediante un processo di produzione che pure soddisfi certi attributi di qualità.
Le origini dell'ingegneria del software. - L'ingegneria del s. costituisce uno dei settori più recenti dell'ingegneria. La sua nascita può essere fatta risalire alla fine degli anni Sessanta, quando l'improvvisa e straordinaria diffusione dell'informatica nelle più diverse realtà applicative e la complessità e criticità delle applicazioni stesse, resero evidente la necessità di operare un approccio di tipo ingegneristico alla produzione del software.
Più precisamente, è consuetudine far risalire la nascita della disciplina all'ottobre 1968, quando si tenne a Garmisch-Partenkirchen (Germania) una conferenza promossa dalla NATO, che riunì i massimi specialisti dell'informatica a livello mondiale e che s'intitolò appunto Software Engineering. Tale termine, più che descrivere uno stato di fatto, esprimeva un auspicio: che la produzione di s. potesse raggiungere gli elevati standard qualitativi e quantitativi tipici di altri settori dell'ingegneria, in modo da permettere un passaggio dallo stadio artigianale, se non addirittura creativo-caotico, in cui versava all'epoca la produzione di s., verso uno stadio industriale maturo e stabile. A tal fine, venne discussa la necessità che il settore del s. si dotasse di fondamenti teorici e di metodologie di progettazione e sviluppo che guidassero nella produzione delle applicazioni informatiche, in maniera analoga a quanto accade in altri settori dell'ingegneria. Nell'ambito della conferenza di Garmisch del 1968 si parlò di ''crisi del software'': malgrado la diffusione crescente di s. in ogni settore dell'industria e dei servizi, erano all'ordine del giorno le esperienze di progetti i cui costi e tempi di sviluppo superavano di gran lunga le previsioni, di progetti di qualità insoddisfacente, o addirittura di progetti falliti. La crisi del s. non venne risolta negli anni Settanta. Un noto studio del Government Accounting Office degli USA del 1979 riportava un'analisi di nove progetti s. (intesi rappresentare un tipico campione), dalla quale emergeva che: 3,2 milioni di dollari erano stati spesi per sviluppi di applicazioni mai consegnate; 2 milioni di dollari erano stati spesi per sviluppi di applicazioni consegnate, ma mai utilizzate; 1,3 milioni di dollari erano stati spesi per sviluppi abbandonati o rimodificati; 0,2 milioni di dollari erano stati spesi per sviluppi di applicazioni utilizzate, ma solo dopo consistenti modifiche; soltanto 0,1 milioni di dollari erano stati spesi per sviluppi di applicazioni effettivamente utilizzate come erano state consegnate.
Neanche negli anni Ottanta la crisi del s. ha trovato soluzione. Sono state sviluppate applicazioni in cui la mancata identificazione dei requisiti dell'utente ha portato a costose modifiche, anche radicali, che è stato necessario realizzare dopo la consegna del prodotto. Il fenomeno è ancora più grave in applicazioni di elevata criticità, cui è richiesto un livello di sicurezza e affidabilità assai elevato, che è difficile raggiungere con l'applicazione delle metodologie di progetto e di certificazione oggi usate da chi sviluppa software. Per es., la rivista Computer Weekly nel novembre 1989 segnalava il caso del progetto Folios, un sistema informativo con elevatissime capacità di controllo della sicurezza negli accessi sviluppato per il governo britannico, che fu cancellato per fallimento nel 1989, dopo 4 anni di sviluppi e un investimento di 3,5 milioni di sterline. Così pure, la rivista Flight International nel 1990 riportava che malfunzionamenti del s. causavano lo spegnimento di un motore degli aerei Boeing 747-400 in certe condizioni di volo con pilota automatico.
Malgrado gli sviluppi spettacolari, la crisi del s. perdura soprattutto in ragione della mancata applicazione al s. di metodi standard di tipo ingegneristico e manageriale. A ciò va aggiunta un'inadeguata disponibilità di metodologie generali assestate, corrispondenti a quelle che sono quotidianamente usate nella progettazione nei settori più maturi dell'ingegneria. Spesso, infine, l'uso di metodologie viene ignorato nella pratica quotidiana da chi sviluppa s. a causa sia di una carente formazione professionale dei progettisti, sia di scelte manageriali sbagliate. Esistono però anche delle ragioni di fondo intrinseche alla natura del problema, che fanno sì che le difficoltà della produzione di s. non possano essere completamente rimosse.
Innanzitutto va segnalata la ''complessità'' delle applicazioni, causata dall'interazione del s. con complessi sistemi esterni: da sistemi meccanici o elettrici, nel caso dei sistemi di automazione, a sistemi sociali od organizzativi, nel caso di sistemi informativi. La complessità è dovuta inoltre intrinsecamente al s., in quanto ''materiale'' di lavoro. Il s. non ha una struttura regolare, come altri materiali più tradizionali. Per es., nel caso del progetto di un ponte, il progettista può essere sicuro che se il ponte, in certe condizioni, è in grado di sostenere un certo carico, allora è in grado di sostenere qualunque altro carico inferiore nelle stesse condizioni. Nel caso del s., invece, la dimostrazione che un certo programma funziona correttamente con certi valori dei dati d'ingresso, nulla assicura circa il corretto funzionamento con valori diversi. In base a queste considerazioni, si dice spesso che le proprietà del s. mancano di ''continuità''. Un'altra difficoltà intrinseca è quella dovuta alla definizione dei requisiti di sistema. Da un lato, gli specialisti di s. trovano che i committenti spesso non sanno esattamente ciò che vogliono. Qualora invece i requisiti siano chiari al committente, sorge spesso un problema di comunicazione tra questi e gli esperti informatici. Infine i requisiti che il progettista di s. vorrebbe stabili, sono comunque destinati a evolvere nel tempo, anche se inizialmente sono stati colti correttamente. L'''evoluzione'' può essere imputata a fattori esterni (per es., un cambiamento legislativo che influenza certe operazioni contabili) o a fattori interni: usando l'applicazione gli utenti si rendono conto di altre possibilità per migliorare il loro lavoro, e ciò comporta la modifica di certe funzionalità offerte dal sistema o l'aggiunta di nuove funzionalità. Questa situazione è confermata dall'osservazione sperimentale secondo cui i sistemi più usati sono anche quelli che più sono chiamati a evolvere nel tempo. L'evoluzione del s. è resa possibile dalla sua facilità di modifica, che costituisce però un'ulteriore sorgente di problemi. Se modificare il s. è in linea di principio facile (basta un editor per modificare il testo di un programma), non è altrettanto facile ottenere con la modifica il nuovo funzionamento richiesto. La mancanza di continuità, a cui abbiamo fatto cenno, fa sì che cambiamenti apparentemente piccoli e locali (per es., il cambiamento di una variabile in un'espressione) possano avere effetti globali imprevisti. Le stesse modifiche che vengono effettuate per rimuovere errori possono spesso causare inavvertitamente l'introduzione di nuovi errori. Infine, i problemi di modificabilità sono resi più difficili in quanto possono interferire con il lavoro di gruppo: la modifica a certe parti di un programma fatta da un programmatore può rendere non funzionante il modulo su cui sta lavorando un altro programmatore. Queste difficoltà sono ulteriormente aggravate dall'''invisibilità'' del software. Tutte le ingegnerie tradizionali fanno riferimento alla produzione di beni fisici, che possono essere osservati visivamente. Il s. è invece invisibile e non osservabile. Anche se negli ultimi anni sono stati fatti tentativi e numerosi passi in avanti per produrre delle rappresentazioni visuali del s., permane la difficoltà concettuale a produrre e analizzare entità completamente astratte.
Le caratteristiche che abbiamo osservato (complessità, mancanza di continuità, evoluzione, invisibilità) rendono il prodotto s. atipico rispetto ai prodotti industriali tradizionali. Tali diversità sono alla base dell'impossibilità a trasferire in maniera diretta all'industria del s. i metodi e le tecniche che hanno trovato applicazione in altri settori industriali.
Il software: prodotto, processo e qualità. - Volendo definire le qualità del s., si deve osservare innanzitutto che si tratta di concetti alquanto elusivi, difficili da caratterizzare in maniera rigorosa e, a maggior ragione, formale e quantitativa. Da un lato occorre distinguere tra le qualità esterne (percepibili da un osservatore esterno che esamina il prodotto o il processo) e quelle interne (osservabili in base alla struttura interna del prodotto o processo); dall'altro occorre distinguere tra il prodotto e il processo con il quale questo viene sviluppato. Se, in ultima analisi, l'obiettivo è quello di sviluppare prodotti che risultino competitivi sul mercato in relazione alla propria qualità esterna, le qualità interne e le qualità del processo sono quelle che permettono di ottenere gli standard desiderati di qualità esterne.
Un primo insieme importante di qualità esterne di prodotto è quanto viene spesso denotato con i termini ''affidabilità'', ''correttezza'', ''robustezza'', ''sicurezza'' e ''innocuità'', che riguardano concetti tra loro strettamente collegati. Intuitivamente, con il termine affidabilità s'intende che alle funzionalità offerte da un prodotto sia possibile affidarsi. Infatti, anche se il prodotto può generare dei malfunzionamenti, il loro effetto non è mai così serio da impedire un utilizzo dell'applicazione (si noti che il concetto di affidabilità può anche essere definito in maniera matematica, in base a modelli affidabilistici di tipo probabilistico, quali il modello di Musa; v. anche affidabilità, in questa Appendice). Il termine correttezza indica invece la rispondenza del s. ai suoi requisiti funzionali; qualora questi siano definiti in maniera precisa o addirittura formale, la correttezza può essere definita (e dimostrata) in maniera rigorosa (o formale). Con il termine robustezza s'indica la capacità del s. di mantenere un comportamento accettabile anche in corrispondenza di situazioni non specificate in maniera esplicita nel documento di specifica dei requisiti (per es., comandi o dati d'ingresso inaccettabili). Infine, il termine sicurezza sta a indicare l'impossibilità di fare un uso non previsto (o addirittura fraudolento) dell'applicazione, quale l'accesso ad archivi di dati riservati. Un concetto collegato è infine quello di innocuità (safety), che denota invece l'impossibilità per l'applicazione di entrare in uno stato dal quale possono derivare danni irreparabili, per es. nei confronti dell'ambiente o delle persone.
Le prestazioni indicano invece la qualità esterna di un'applicazione che fa un uso efficiente di risorse, quali la memoria e il tempo di esecuzione. Benché questa caratteristica di qualità sia diventata meno pressante grazie alla disponibilità di dispositivi di elaborazione di basso costo, per quanto riguarda sia la memoria che la velocità di esecuzione, la complessità crescente delle applicazioni continua a richiedere che i tempi di risposta si mantengano entro termini accettabili e che la memoria sia sufficiente a supportare dati e applicazioni di dimensioni sempre crescenti. Le prestazioni costituiscono forse il settore per il quale sono disponibili i metodi di verifica più assestati. Per es., la teoria della complessità degli algoritmi consente di caratterizzare in maniera precisa l'andamento asintotico del tempo di calcolo e dell'occupazione di memoria. Le prestazioni possono anche essere valutate mediante simulazione e mediante modelli analitici basati sulla teoria delle code. Una caratteristica di qualità esterna di prodotto che è andata acquistando sempre maggiore importanza è l'usabilità, ossia la facilità e immediatezza di uso di un'applicazione, che permetta anche a un utente inesperto di trarre profitto dal suo impiego. L'aspetto forse più importante dell'usabilità è costituito dall'interfaccia utente (cioè il modo di realizzare il collegamento tra utente e s.), che sempre più risulta di tipo grafico e interattivo. Anziché interagire con il s. in maniera testuale, digitando sulla tastiera sequenze codificate di caratteri, l'utente può attivare i diversi comandi, che sono rappresentati in maniera grafica sullo schermo, secondo una simbologia autoesplicativa. Si dice anche che le moderne interfacce risultano del tipo WYSIWYG (acronimo che sta per what you see is what you get, "ciò che vedi è ciò che ottieni"), ossia che le informazioni visualizzate sullo schermo indicano in maniera immediata l'effetto di ogni operazione, e l'uso di dispositivi di puntamento (quali il mouse) di tali informazioni consente una selezione e manipolazione diretta delle informazioni visualizzate e delle relative operazioni.
Fondamentale risulta poi la qualità di manutenibilità, intesa come la facilità e l'economicità con la quale al s. possono essere apportate le modifiche che si rendono necessarie dopo il suo rilascio. La manutenibilità risulta scomponibile in due fattori: la capacità di correzione di errori e la capacità di evoluzione dell'applicazione per adattamenti o per miglioramenti. In entrambi i casi, la caratteristica di qualità interna di comprensibilità del prodotto, e in particolare la sua modularità che deriva dall'adozione di apposite tecniche di progettazione, risultano fondamentali al fine di garantire che il prodotto possa essere modificato in maniera efficace. Un particolare caso di adattamento è quello dovuto alla possibilità di adattare l'applicazione a diverse architetture di elaboratore e di s. di base: in tal caso si parla spesso di portabilità dell'applicazione. Così pure, come caso speciale della facilità di evoluzione, può essere vista la riusabilità, vale a dire la possibilità di riusare parti di un'applicazione per la costruzione di nuove applicazioni, evitando che ogni volta si ricostruiscano gli stessi componenti, ma procedendo invece per adattamento di componenti preesistenti. La riusabilità è in effetti una caratteristica importante di molti settori ingegneristici, specie i settori più maturi: basti pensare al riuso di componenti standard nell'elettronica o all'uso di prefabbricati nell'ingegneria civile. Un concetto correlato è quello di interoperabilità, con il quale si vuol caratterizzare un'applicazione che s'integra e opera con altre: così come, per es., un sistema di alta fedeltà può essere assemblato mediante componenti diversi (amplificatore, casse acustiche, lettore di compact disc, ecc.), eventualmente di produttori diversi, così si vorrebbe che più componenti s. (per es., un foglio elettronico, un sistema d'invio di fax, un sistema di gestione di archivi, ecc.) possano operare in maniera congiunta senza difficoltà.
Un'ultima importante caratteristica di qualità, che riguarda il processo, è la produttività con la quale le applicazioni vengono sviluppate dagli ingegneri del software. Anche in assenza di un metodo largamente condiviso che definisca in maniera rigorosa che cosa s'intenda per produttività e come la si possa misurare, è opinione largamente diffusa che la produttività che si raggiunge oggi debba (e possa) in futuro migliorare di ordini di grandezza, sia attraverso un crescente riuso di componenti, sia mediante l'uso di adeguata tecnologia di supporto allo sviluppo, al fine di ridurre i costi del s., che oggi costituiscono almeno l'80% dei costi complessivi dei sistemi informatici.
Il ciclo di vita del software. - Il ciclo di vita del s. (o processo s.) definisce un modello di riferimento tecnico e organizzativo per lo sviluppo del software. Esso è basato su una visione del processo, inteso come una successione di fasi e attività attraverso cui evolve lo sviluppo delle applicazioni: dal concepimento iniziale del sistema da realizzare, alla sua manutenzione e, infine, al suo ritiro dall'operatività. Esistono diversi modelli di ciclo di vita: da quello tradizionale ai più recenti basati su una maggiore flessibilità e adattabilità.
Il modello tradizionale, detto anche ciclo di vita a cascata, nasce come reazione a uno sviluppo del s. disordinato e non pianificato, e pertanto si presenta come un tentativo di rigida razionalizzazione. Il modello identifica una progressione prefissata di fasi per lo sviluppo e definisce con precisione i prodotti (semilavorati) che ciascuna fase deve produrre. Con riferimento all'esempio di fig. 1, la fase di analisi e specifica dei requisiti produce un documento di specifica, che costituisce il punto di partenza per la fase di progettazione; questa, a sua volta, produce un documento di progetto, che viene utilizzato per la realizzazione (programmazione e test di unità). Infine, il sistema completamente realizzato viene sottoposto al collaudo finale, prima del suo rilascio. Si può così osservare che, secondo il modello a cascata, i semilavorati prodotti da una fase costituiscono i dati d'ingresso per la fase successiva e il modello forza una progressione lineare delle fasi, in modo tale da impedire che si realizzino dei disordinati ritorni all'indietro per rifare attività che avrebbero dovuto essere già completate. Impedire i ricicli (e ''linearizzare'' il processo) diventa necessario per poter meglio prevedere e controllare il processo di sviluppo. Nel seguito verranno illustrati i contenuti delle più importanti fasi e le metodologie che in ciascuna di esse possono essere utilizzate. Tali contenuti e metodologie sono in larga misura indipendenti dal modello di ciclo di vita all'interno del quale essi vengono organizzati. L'obiettivo principale del modello a cascata è quello di gestire in maniera organizzata il processo, al fine di realizzare e consegnare i prodotti nei tempi previsti, all'interno del budget prefissato e avendo raggiunto un accettabile livello di qualità. Le attività che vengono sviluppate dopo il rilascio dell'applicazione, secondo questo modello, vanno complessivamente sotto il termine di manutenzione. Si tratta di un termine divenuto di uso ormai comune, ma largamente inappropriato, in quanto normalmente la necessità di manutenzione deriva da fenomeni d'invecchiamento di un prodotto, che possono causare logoramenti o guasti nelle sue parti. Il s., al contrario, non è soggetto a usura per il fatto di essere eseguito: la necessità di manutenzione deriva pertanto da altri motivi che, in parte, sono già stati citati nei precedenti paragrafi.
L'esperienza dimostra che, in un modello a cascata, la manutenzione costituisce la fase più onerosa, pari a circa il 60% dei costi complessivi. Essa, anziché l'eccezione, è dunque la regola: va capita, prevista, pianificata e gestita. Tre sono gli aspetti fondamentali delle attività di manutenzione. Innanzitutto, la manutenzione correttiva, che consiste nella rimozione degli errori presenti nell'applicazione (e cioè nell'eliminazione degli scostamenti esistenti tra specifica dei requisiti e prodotto realizzato). Poiché ogni modifica apportata al s. provoca l'introduzione di nuovi errori, questa componente della manutenzione resta presente per tutta la vita dell'applicazione, arrivando a pesare per circa il 20% dei costi complessivi di manutenzione. Un secondo aspetto, che assorbe un altro 20% circa di costi di manutenzione, è la cosiddetta manutenzione adattativa, e cioè gli interventi di modifica che si rendono necessari non perché il s. di per sé debba cambiare, ma perché certe mutate condizioni ambientali impongono dei cambiamenti nel software. Si pensi, per es., alla necessità di far fronte a cambiamenti nella versione del sistema operativo delle macchine sulle quali il s. opera, o a mutamenti legislativi che impongono modifiche nelle aliquote fiscali di certe categorie di prodotti all'interno di un'applicazione per la fatturazione. Un terzo aspetto, infine, che assorbe più del 50% dei costi di manutenzione, è la cosiddetta manutenzione perfettiva, e cioè gli interventi di modifica che o variano le funzionalità offerte, o aggiungono nuove funzionalità, o migliorano le prestazioni, ecc. In generale, questi tipi di interventi si rendono necessari o perché la specifica iniziale non ha colto con precisione i requisiti dell'utente, o perché i requisiti sono andati evolvendo.
L'elevata incidenza dei costi di manutenzione ha fatto nascere l'esigenza di modelli che meglio si prestassero a strutturare il processo di sviluppo del software. Per far fronte ai costi di manutenzione correttiva e adattativa, si è cercato di mettere a punto metodi e strumenti per lo sviluppo di s. affidabile e facilmente modificabile. La produzione di s. modificabile contribuisce a ridurre anche i costi della manutenzione perfettiva, ma per far fronte a questa è necessario abbandonare il rigido modello di ciclo di vita a cascata.
I modelli alternativi di ciclo di vita si basano tutti su alcuni principi fondamentali, quali la prototipazione e l'incrementalità. L'obiettivo è quello di realizzare modelli flessibili, che consentano una migliore visibilità del processo e che offrano quindi la possibilità d'intervenire ad apportare delle modifiche in corso di sviluppo, e non alla fine, quando è ormai tardi e ogni intervento risulta difficile e costoso. Attraverso la prototipazione si cerca di realizzare in maniera rapida ed economica un'applicazione-pilota (prototipo) che, per le parti ritenute più critiche, ''assomiglia'' al prodotto che dovrà essere realizzato. Il prototipo dovrà però servire a calibrare i requisiti mediante un modello che può essere direttamente sperimentato dal committente; ciò potrà pertanto consentire di minimizzare la probabilità che errori nella specifica dei requisiti portino a sviluppare prodotti che non corrispondono ai desideri del committente. Il prototipo, una volta assolti i compiti per i quali è stato sviluppato, può essere o scartato, per dar luogo a un successivo sviluppo realizzato attraverso un tradizionale processo a cascata (prototipo usa e getta), oppure trasformato per ''incrementi'' successivi nel prodotto finale, cioè attraverso successive modifiche (prototipo evolutivo). In quest'ultimo caso occorre ovviamente che il metodo di progettazione utilizzato garantisca che questa progressiva trasformazione (incrementalità) possa avvenire in maniera semplice e affidabile. Un'ulteriore modalità di sviluppo incrementale è quella che all'interno di una complessa applicazione cerca d'identificare le parti (sottosistemi) che si possono sviluppare indipendentemente. Anziché condurre lo sviluppo completo del sistema in maniera monolitica, la preventiva individuazione di sottosistemi consente di realizzare e consegnare al committente tali sottosistemi parziali, dal cui uso pratico sono però ricavabili utili esperienze, che permettono di calibrare meglio gli sviluppi delle parti o sottosistemi restanti.
Analisi e specifica dei requisiti. - Obiettivo della fase di analisi e specifica dei requisiti è quello di analizzare gli obiettivi di qualità dell'applicazione e di fornirne una descrizione precisa ed esauriente. In particolare, in questa fase devono essere definiti i requisiti funzionali dell'applicazione, in base ai quali risultano poi definite qualità quali la correttezza e l'affidabilità. Tradizionalmente, questa fase risulta assai trascurata da chi sviluppa software. Spesso s'inizia a realizzare un'applicazione prima di aver tentato di capire esattamente che cosa l'applicazione dovrà fare e, ancor più spesso, è lo stesso documento che raccoglie la specifica dei requisiti a risultare poco preciso, incompleto, ambiguo. Quando la specifica dei requisiti è deliberatamente poco approfondita all'inizio, a vantaggio di un approccio basato sulla prototipazione, spesso purtroppo non ci si cura alla fine di produrre una specifica precisa ed esauriente che documenti il risultato dell'attività di prototipazione, e che possa servire più avanti come documento di riferimento a fronte di ulteriori modifiche che si rendessero necessarie nel tempo.
Il documento di specifica dei requisiti fa spesso parte integrante delle pattuizioni contrattuali tra chi sviluppa l'applicazione e il committente: il primo s'impegna (nei tempi, nei modi e con i costi pattuiti) a realizzare l'applicazione come da specifica; il secondo s'impegna ad accettare l'applicazione qualora essa soddisfi i requisiti specificati. La specifica di requisiti, purtroppo, tradizionalmente avviene in maniera informale, utilizzando il linguaggio naturale. Gli svantaggi del linguaggio naturale, che pure utilizziamo quotidianamente nella comunicazione tra persone, risiedono nella scarsa possibilità di rigore e precisione, nella potenziale ambiguità di espressione, nell'impossibilità di un trattamento (automatico o meno) delle specifiche, per valutarne la completezza e la consistenza. Una specifica informale in linguaggio naturale fornisce pertanto indicazioni inaffidabili su come procedere al progettista dell'applicazione. Una diversità d'interpretazione dei requisiti da parte dei committenti e dei progettisti può pertanto portare ad applicazioni che richiedono profonde modifiche per essere accettate. Fatto ancor più grave, esse possono portare a divergenze anche gravi di valutazione da parte dei progettisti e dei committenti: per i primi, certe richieste di modifica potrebbero esser considerate richieste di manutenzione perfettiva (pertanto a carico del committente, da un punto di vista dei costi), mentre per i secondi esse potrebbero esser considerate manutenzione correttiva (pertanto a carico dei progettisti).
In un ambito completamente diverso si collocano i linguaggi formali per la specifica dei requisiti. Si tratta in tal caso di linguaggi artificiali, basati su concetti matematicamente definiti, che consentono una specifica rigorosa dei requisiti funzionali di un sistema, nonché la possibilità di assoggettare le specifiche a procedure rigorose di analisi. Tali linguaggi costituiscono a tutt'oggi un importante terreno di ricerca e hanno trovato un limitato impiego nel mondo applicativo. Negli ultimi anni si sono invece diffusi i metodi di specifica basati su linguaggi semiformali, che costituiscono una classe intermedia tra i linguaggi formali e il linguaggio naturale. Essi sono in parte basati su concetti formalizzati (spesso di natura grafica) e, in parte, contengono aspetti informali. Si tratta di linguaggi d'impiego piuttosto semplice e intuitivo, che per essere usati non richiedono speciali competenze di natura matematica. Gli aspetti informali presenti nella notazione, tuttavia, fanno sì che spesso le specifiche contengano taluni aspetti ambigui o imprecisi e che non sia possibile pertanto analizzare le proprietà delle specifiche usando il rigore dei ragionamenti matematici.
È possibile operare un'ulteriore classificazione tra i diversi metodi di specifica, al fine di portare a una loro migliore comprensione e di porre le basi per una loro classificazione precisa. Un linguaggio si dice operazionale se il sistema viene specificato mediante un modello che opera in maniera analoga al comportamento funzionale del sistema che si vuole specificare. Si dice invece descrittiva una specifica che descrive il sistema desiderato definendone le proprietà. Nel seguito vedremo schematicamente linguaggi di specifica di tipo semiformale e formale, di tipo operazionale e di tipo descrittivo.
Un tipico linguaggio semiformale operazionale è costituito dai Diagrammi di Flusso dei Dati (DFD). Un DFD specifica un sistema scomponendolo in funzioni attraverso le quali fluiscono i dati; questi possono anche fluire da e verso l'esterno e possono essere memorizzati in archivi. Una tipica simbologia grafica è illustrata nell'esempio di fig. 2, che descrive il funzionamento di un sistema di controllo dei pazienti di un ospedale. Una specifica mediante DFD può essere fornita per livelli di dettaglio progressivi, scomponendo una funzione (definita da una bolla) in un DFD che la dettaglia. Per es., in fig. 3, la funzione ''monitoraggio paziente'' viene scomposta mediante l'enucleazione delle funzioni ''monitoraggio centrale'', ''monitoraggio locale'', ''aggiorna archivio'' e ''genera rapporto''. La composizione termina quando le funzioni del DFD sono così semplici da essere comprensibili immediatamente, senza ulteriori scomposizioni. Gli aspetti informali del DFD stanno da un lato nel fatto che, quando la scomposizione termina, le funzioni associate alle bolle sono definite in linguaggio naturale, e dall'altro nel fatto che il DFD non descrive per nulla come il flusso di controllo passa da una funzione all'altra del DFD. Questi aspetti sono trascurati o sono espressi in maniera informale. Il limite della notazione in termini di formalità si riflette in limiti in termini di possibilità di analisi della specifica, per es., per la verifica della correttezza. Poiché i DFD si limitano sostanzialmente a definire la sintassi del formalismo grafico, le sole verifiche possibili sono di ordine sintattico. Per es., è richiesto che il diagramma che dettaglia una bolla abbia un numero di flussi entranti e uscenti pari a quelli della bolla; specifiche che non rispettano questo vincolo devono essere considerate sintatticamente scorrette.
Un linguaggio di specifica che privilegia la descrizione del flusso di controllo rispetto alla definizione degli aspetti funzionali è fornito dagli Automi a Stati Finiti (ASF). Gli ASF costituiscono uno dei formalismi classici più studiati e versatili dell'informatica e trovano impiego nei settori più diversi (dalla descrizione dei componenti circuitali degli elaboratori a quella di linguaggi di programmazione). Per come vengono in pratica normalmente usati nell'attività di specifica, essi devono essere considerati dei semi-formalismi di tipo operazionale, in quanto fanno ampio uso di annotazioni informali per specificare aspetti complementari al flusso di controllo. Intuitivamente, un ASF è caratterizzato da un insieme finito di stati (rappresentati graficamente da cerchi) e un insieme finito di transizioni (rappresentate da frecce che connettono due stati). L'ASF di fig. 4 specifica il funzionamento di un impianto, nel quale possono sorgere due situazioni anomale: supero del limite di tolleranza del volume del liquido immagazzinato e supero del limite di tolleranza della temperatura. L'impianto può cercare di far fronte separatamente a ciascuna delle due situazioni di emergenza; se la risposta al malfunzionamento non ha esito favorevole o se entrambe le anomalie si manifestano, l'impianto viene posto nello stato di fermo; altrimenti, l'impianto viene riportato nella situazione di funzionamento normale entro 30 s. Si osservi che l'ASF di fig. 4 fornisce solo una visione schematica parziale del funzionamento dell'impianto; esso dev'essere corredato di spiegazioni accessorie espresse in modo informale (per es., il fatto che il ritorno nello stato di funzionamento normale deve avvenire entro 30 s) per poter esprimere esattamente il funzionamento dell'impianto. Classi particolari di ASF sono gli automi accettori, per i quali è definito uno stato iniziale e uno stato finale, e gli automi trasduttori, per i quali le transizioni avvengono dietro l'effetto di certi ingressi e la transizione genera a sua volta una corrispondente uscita.
Le reti di Petri costituiscono un formalismo che estende gli ASF, nel senso che permettono di descrivere in maniera formale la cooperazione di due o più ASF e, inoltre, permettono di rappresentare anche sistemi caratterizzati da un numero infinito di stati. Intuitivamente, una rete di Petri è caratterizzata da un insieme finito di posti (denotati graficamente da cerchi), da un insieme finito di transizioni (denotate graficamente da rettangoli) e da un insieme finito di flussi che collegano posti a transizioni e transizioni a posti. La rete di Petri è un formalismo operazionale: lo stato di un sistema è rappresentato mediante una marcatura della rete (definita da un intero non negativo associato a ciascun posto e rappresentata graficamente da un insieme di gettoni, o token, memorizzati nei posti). L'evoluzione di stato di una rete di Petri avviene producendo una marcatura della rete a partire da un'altra marcatura, attraverso lo scatto di una transizione. Una transizione può scattare se tutti i posti che hanno un arco diretto verso la transizione contengono almeno un gettone. L'effetto dello scatto di una transizione modifica la marcatura: viene ridotto di 1 il numero dei gettoni presenti in ciascun posto che ha un arco diretto verso la transizione e viene incrementato di 1 il numero di gettoni memorizzati in ciascun posto collegato con un arco uscente dalla transizione. La rete di fig. 5 rappresenta un sistema composto da un magazzino di capacità illimitata, un produttore (che ripetitivamente produce un nuovo dato e lo deposita nel magazzino) e un consumatore (che ripetutamente preleva un dato dal magazzino e lo consuma). Inizialmente, come mostrato in detta figura, il produttore è pronto a scrivere un dato nel magazzino (ciò è rappresentato dalla presenza di un gettone nel posto p1), il magazzino è vuoto (nessun gettone è presente nel posto p3), mentre il produttore è pronto a leggere un dato dal magazzino (ciò è rappresentato dalla presenza di un gettone nel posto p4). La eventuale presenza di un gettone nei posti p2 e p4 denoterebbe invece, rispettivamente, che il produttore è pronto a produrre un nuovo dato e il consumatore è pronto a consumare il dato appena letto dal magazzino. Ogni transizione della rete modella un'azione o un evento: la scrittura di un dato nel magazzino è rappresentata dallo scatto di t2, la produzione di un nuovo dato da scrivere dallo scatto di t1, la lettura dal magazzino dallo scatto di t3 e il consumo del dato letto dallo scatto di t4. Le reti di Petri sono spesso utilizzate in maniera semiformale, mediante l'uso di annotazioni informali accanto ai concetti formali propri delle reti. Esistono però anche delle estensioni formalmente definite delle reti di Petri, spesso chiamate reti di Petri di alto livello, che formalizzano aspetti quali la definizione delle operazioni definite dalle transizioni, dei dati associati ai gettoni, delle durate temporali delle azioni, ecc.
Un esempio di linguaggio semiformale di specifica di tipo descrittivo è costituito dai Diagrammi Entità-Relazione (DER). Un DER descrive i dati sui quali un'applicazione è chiamata a operare, fornendo una descrizione concettuale delle relazioni logiche tra di essi e dei vincoli che devono intercorrere. I DER sono un linguaggio semiformale molto usato nelle applicazioni delle basi di dati, in cui la specifica dei dati costituisce ovviamente l'aspetto più rilevante. Il linguaggio è intrinsecamente incompleto, in quanto non consente di specificare altri aspetti, quali le operazioni da effettuare sui dati e i flussi di controllo che descrivono l'attivazione delle diverse operazioni. Tali aspetti vengono pertanto descritti a parte mediante altri semiformalismi o descrizioni testuali informali in linguaggio naturale. In fig. 6 è illustrato un esempio di DER che specifica alcuni aspetti riguardanti la struttura di un testo letterario: l'entità ''personaggi'' descrive un insieme di elementi (i personaggi del testo) che hanno un nome, un cognome e un ruolo, l'entità ''capitoli'' descrive un insieme di elementi (i capitoli del libro) che hanno un numero e un titolo, la relazione ''appare'' descrive l'associazione tra personaggi e capitoli nei quali i personaggi appaiono. Le informazioni elementari che costituiscono gli elementi delle diverse entità si chiamano ''attributi'', e vengono descritte con una notazione analoga a quella usata per definire i record di un convenzionale linguaggio di programmazione. È possibile specificare aspetti ulteriori: se la relazione debba essere uno a uno, uno a molti o molti a molti, se esistano vincoli d'integrità quali l'esistenza di elementi di un'entità (per es., un personaggio) senza che esista un elemento associato dell'entità collegata mediante una relazione (nell'esempio, un capitolo nel quale il personaggio appare).
Progettazione. - L'obiettivo della fase di progettazione è quello di scomporre un sistema, spesso complesso e di grande dimensione, in parti distinte che ne consentano lo sviluppo separato da parte dei diversi membri di un gruppo di lavoro. Per raggiungere quest'obiettivo è necessario definire un'architettura modulare per il sistema, ossia quali sono i moduli che costituiscono il sistema e quali sono le relazioni che intercorrono tra di essi. Per ciascun modulo, dev'essere definita rigorosamente l'interfaccia: i servizi (procedure, dati, ecc.) che il modulo realizza e rende disponibili (esporta) per altri moduli. I moduli che usano i servizi definiti nell'interfaccia di un altro modulo si dice che ne sono clienti; tra di essi si dice che intercorre una relazione d'uso, in quanto il modulo cliente usa le risorse esportate dall'altro modulo. Una buona architettura dev'essere caratterizzata da un'elevata coesione e indipendenza. La coesione significa che ciascun modulo svolge un compito ben preciso, sicché tutto ciò che esso racchiude concorre a fornire le funzionalità esportate. Al contrario, un modulo scarsamente coeso raggruppa entità logicamente scorrelate e pertanto rappresenta il risultato di un'attività di progettazione nella quale le entità raggruppate nel modulo sono state identificate in maniera casuale. L'indipendenza significa che, per la realizzazione delle proprie funzionalità, ciascun modulo dipende in maniera limitata da altri moduli. Un'architettura in cui i moduli abbiano elevata coesione e indipendenza facilita il loro sviluppo separato e parallelo da parte di diverse persone, con conseguente riduzione dei tempi di sviluppo.
Un importante criterio che conviene seguire nella progettazione di un sistema è quello di isolamento delle informazioni (information hiding). Secondo tale criterio, è opportuno che le interfacce di un modulo nascondano i dettagli del funzionamento interno del modulo, rendendo l'interfaccia il più possibile stabile rispetto a cambiamenti interni al modulo. Così facendo, l'interfaccia fornisce una visione astratta e semplificata di ciò che il modulo svolge, in quanto i dettagli del funzionamento risultano nascosti all'interno del modulo: ciò semplifica la progettazione dei moduli clienti, in quanto basta che essi conoscano le informazioni semplificate che descrivono l'interfaccia per poter usare un certo modulo. Inoltre, è importante che i moduli nascondano al proprio interno le informazioni che sono più probabilmente destinate a cambiare e che le interfacce risultino invece indipendenti da tali cambiamenti. Così facendo, la futura evoluzione del sistema a fronte di eventuali cambiamenti nei requisiti (che abbiamo visto essere così frequenti nel s.) può avvenire in maniera semplice, senza richiedere riprogettazioni complessive, purché l'effetto di un cambiamento si rifletta in una modifica locale a un modulo e non si propaghi in una modifica della sua interfaccia, che a sua volta richiederebbe una modifica dei moduli clienti. Il concetto d'isolamento delle informazioni è quello che sta alla base di moduli che realizzano tipi di dati astratti, che a loro volta costituiscono il fondamento della progettazione orientata a oggetti. Un tipo di dato astratto è un modulo che nasconde i dettagli realizzativi di una struttura di dati ed esporta soltanto le operazioni che consentono di generarne diversi esemplari e di operare su di essi, mentre i sottoprogrammi che realizzano le operazioni risultano nascosti all'interno del modulo. Secondo i canoni della progettazione orientata a oggetti, l'architettura di un sistema s. viene definita attraverso una scomposizione in una collezione di tipi di dati astratti, tra i quali, oltre alla sopra menzionata relazione d'uso, risulta definibile anche la relazione di ereditarietà. La relazione di ereditarietà consente di estendere o specializzare moduli preesistenti (per es., moduli prelevati da una biblioteca di componenti riusabili).
Realizzazione. - La fase di realizzazione (o implementazione) consiste nel tradurre l'architettura definita nella fase di progettazione in moduli di programma scritti in un certo linguaggio di programmazione. Tale traduzione risulta tanto più diretta quanto più alto è il livello dei linguaggi utilizzati (v. anche linguaggi programmativi, in questa Appendice). Nell'effettuare questa traduzione, devono anche essere progettati e codificati gli algoritmi interni a ciascun modulo, attraverso i quali vengono realizzate le funzionalità esportate dal modulo stesso. Durante la fase di realizzazione vengono anche effettuati i primi collaudi sui singoli moduli. Si tratta del test di modulo, con il quale si cerca di esercitare ciascun modulo sia in base alla sua struttura interna (test strutturale), che in base alla sua specifica (test funzionale). Qualora il test evidenzi la presenza di errori nel programma, ci si preoccupa di rimuovere gli errori presenti attraverso la cosiddetta attività di debugging.
Controllo di qualità. - Il controllo di qualità è un'attività che risulta distribuita lungo tutto il ciclo di vita. Nelle fasi di analisi e di progettazione tale controllo potrà riguardare aspetti quali l'adesione a certi standard, la consistenza delle specifiche, la loro completezza, la facilità con la quale potranno essere apportate modifiche, ecc. Si tratta di attività di controllo che possono essere fatte in maniera prevalentemente informale, in quanto i documenti a cui si riferiscono sono largamente informali. Pertanto, il controllo di qualità si esplica usualmente attraverso incontri organizzati all'interno dei gruppi di progetto (chiamati ispezioni o walkthroughs). L'obiettivo finale del controllo di qualità è comunque che il prodotto realizzato sia accettabile e quindi che possa essere rilasciato. Tale controllo consiste pertanto in due aspetti: da un lato che il sistema che si sta realizzando verifichi le necessità del committente, dall'altro che esso verifichi le specifiche fornite. Chiaramente, la distinzione tra questi due aspetti (per i quali talvolta si usano, rispettivamente, i termini di ''convalida'' e ''verifica'') deriva dal fatto che le specifiche possono essere erronee, e quindi non cogliere tutti (e correttamente) i requisiti richiesti per l'applicazione, sicché una semplice coerenza del sistema rispetto alla specifica non significa che il sistema realizzato sia comunque alla fine accettabile per il committente. Una delle maggiori speranze riposte nei linguaggi formali di specifica che si stanno oggi sperimentando è che con essi si possa arrivare a una convalida a fondo delle specifiche che preceda il progetto e la realizzazione, allo scopo di limitare il successivo controllo di qualità alla verifica di coerenza interna al progetto.
Nel ciclo di vita a cascata descritto in fig. 1 è stata indicata una fase di collaudo finale, che precede il rilascio dell'applicazione. Per tale collaudo, il metodo usualmente impiegato è quello del test. Talora si distingue tra test di sistema (il test svolto da chi ha sviluppato l'applicazione sul sistema completo, integrato in tutti i suoi componenti) e test di accettazione (il test svolto dal committente nelle condizioni d'impiego effettivo, prima dell'atto formale di accettazione del prodotto). Talora, specie per prodotti di largo consumo quale per es. un word-processor, si distingue tra alfa test, inteso come il test di uso effettivo dell'applicazione fatto all'interno dell'organizzazione che ha sviluppato il prodotto, e beta test, inteso come l'uso fatto da selezionati clienti che si prestano alla sperimentazione del prodotto. L'obiettivo dell'alfa e beta test è di arrivare a collocare sul mercato il prodotto solo dopo che questo ha dimostrato di essere sufficientemente robusto e dopo che il feedback ottenuto da un'utenza controllata e selezionata ha dato risultati soddisfacenti.
Gestione dei processi e dei prodotti. - Le attività fondamentali di gestione dei processi s. sono la previsione, la pianificazione e il controllo, per le quali valgono molti dei metodi e degli strumenti studiati in altri settori dell'ingegneria, pur con le cautele che si devono applicare a un prodotto particolare come il software. Particolarmente atipica e critica risulta l'attività di previsione, che dovrebbe consentire di stimare in maniera accurata il costo e la durata di un progetto. In questo settore sono state avanzate diverse proposte di metodi di stima, il più noto dei quali (COCOMO, COnstructive COst MOdel) è dovuto a B. Boehm. Nessuno di questi, tuttavia, è riuscito a imporsi nella realtà, malgrado l'enorme rilevanza pratica del problema. Oltre alla gestione del processo (in ultima analisi, la gestione delle risorse umane), è di fondamentale importanza per sistemi di grande dimensione tenere sotto controllo la grande quantità di informazioni (dati, programmi, specifiche, piani di lavoro, manuali, ecc.) che vengono sviluppate nel corso del progetto. In ciò risiede il ruolo della gestione delle configurazioni, vale a dire dell'insieme di metodi e strumenti che aiutano a tenere organizzate tutte queste informazioni e le loro relazioni; in particolare, a identificare, tenere correlate e controllare le modifiche a tutti i semilavorati prodotti nel processo software.
Metodologie, strumenti di supporto e ambienti di sviluppo. - Al fine di guidare gli ingegneri del s. nelle attività di sviluppo e manutenzione, standardizzandone per quanto possibile i procedimenti, sono state messe a punto in passato diverse metodologie che cercano di offrire un quadro di riferimento complessivo, con particolare attenzione alle fasi di analisi e progettazione. In particolare, si sono affermate le cosiddette metodologie di analisi e progettazione strutturata, che fanno largo impiego dei DFD per descrivere la scomposizione di sistemi complessi in funzioni, sia a livello dei requisiti, sia a livello delle funzioni svolte dall'implementazione. Più recentemente, sono state proposte metodologie orientate a oggetti, che cercano invece di guidare sia l'analisi che la progettazione attraverso una scomposizione per tipi di dati astratti. Tradizionalmente, queste metodologie sono state di tipo essenzialmente cartaceo: il loro risultato era quello di produrre documentazione secondo certi standard, ma senza particolari ausili di tipo automatico. Possiamo anzi affermare che l'attività di sviluppo di s., se ha avuto l'effetto di contribuire ad automatizzare i settori industriali e dei servizi più disparati, fino a qualche anno fa non era riuscita ad automatizzare se stessa, se non per la fase di realizzazione, per la quale erano disponibili strumenti di supporto alla codifica, quali editors, compilatori, debuggers.
Negli ultimi anni si è assistito sempre più alla disponibilità di nuove classi di strumenti e, addirittura, di insiemi integrati di strumenti che costituiscono ambienti integrati di sviluppo. In particolare, si sono affermate soluzioni designate dall'acronimo CASE (Computer-Aided Software Engineering), che indica il complesso di tecnologia disponibile a supporto dello sviluppo e della manutenzione del software. Innanzitutto esistono strumenti cosiddetti di Upper CASE, che automatizzano l'analisi e la specifica dei requisiti e la progettazione, fornendo per es. un supporto alle metodologie dell'analisi e della progettazione strutturata, attraverso metodi semiformali basati su DFD e DER e notazioni per la descrizione dell'architettura dei sistemi. Per le fasi di realizzazione e test sono disponibili strumenti di Lower CASE, quali i generatori automatici di parte del codice a partire dalla specifica, strumenti di debugging, generatori di dati di test, strumenti per la gestione del test e l'archiviazione dei risultati. Esistono poi strumenti di gestione del processo, per es. attraverso diagrammi PERT (Program Evaluation and Review Technique) e carte di Gantt, strumenti per la previsione dei tempi e dei costi, strumenti per la gestione delle configurazioni. Infine sono disponibili strumenti di supporto alla manutenzione, quali analizzatori e ristrutturatori di codice, spesso definiti di reverse engineering o re-engineering. Poiché con il passare del tempo, per effetto delle continue modifiche, la struttura del s. tende a deteriorarsi, gli strumenti di reverse engineering aiutano a ricostruire uno stato coerente del progetto, al fine di facilitare la successiva ri-ingegnerizzazione.
Bibl.: B. Boehm, Software engineering economics, New York 1981; A.S. Fisher, CASE-using software development tools, ivi 1991; C. Ghezzi, M. Jazayeri, D. Mandrioli, Fundamentals of software engineering, Englewood Cliffs 1991; C. Ghezzi, A. Fuggetta, S. Morasca, A. Morzenti, M. Pezzè, Ingegneria del software, Milano 1991; Software engineer's reference book, a cura di J. McDermid, Oxford 1991.
Diritto. - Il problema della protezione giuridica del s. è stato per lungo tempo privo di una specifica normativa di riferimento; per tale motivo possibilità diverse di tutela sono state rinvenute nelle norme riguardanti i brevetti per invenzioni industriali, il diritto d'autore, la concorrenza sleale. L'elaborazione dottrinale e l'evoluzione giurisprudenziale, preclusa per i suoi limiti la tutela brevettuale, hanno ritenuto preferibile l'ipotesi di proteggere i programmi per elaboratore (il s. costituisce, appunto, l'"elemento immateriale" del computer, in quanto composto da informazioni e da istruzioni) qualificandoli come opere dell'ingegno. La rapida diffusione degli elaboratori elettronici e dei relativi programmi, i frequenti atti di pirateria e di plagio che ne accompagnano l'impiego, il forte rilievo economico assunto dal settore hanno determinato l'emanazione di norme contro la cosiddetta ''criminalità informatica'' che, venendo a colmare un vuoto legislativo, riconoscono sotto il profilo penale la rilevanza degli atti di siffatta natura.
Dando un'impostazione organica e sistematica a questa materia, la l. 23 dicembre 1993 n. 547 si è venuta ad affiancare al decreto legisl. 29 dicembre 1992 n. 518 che ha disciplinato la tutela giuridica del s. introducendo sanzioni di natura penale per le fattispecie di duplicazione, commercializzazione e detenzione di copie di programmi non autorizzate. In particolare il decreto legisl. 518/1992 ha risolto in senso positivo la controversa questione, postasi alla dottrina nella mancanza di una normativa specifica, se il s. potesse godere o meno della tutela accordata alle opere dell'ingegno e che è positivamente riconosciuta anche dalla giurisprudenza della Cassazione. A sua volta la l. 547/1993, operando direttamente sulla normativa in materia di diritto d'autore (l. 22 aprile 1941 n. 633), ha provveduto con l'art. 9 a introdurre nel codice penale l'art. 635-bis che configura una specifica fattispecie di danneggiamento avente per oggetto "la distruzione, il deterioramento o la messa fuori uso di sistemi informatici o telematici altrui ovvero di programmi informatici altrui".
Nell'ambito degli abusi informatici la l. 547/1993 ha ricondotto sia i fatti o gli atti illeciti effettuati contro l'elaboratore elettronico, sia i fatti o gli atti illeciti compiuti con l'ausilio dell'elaboratore elettronico. Nel primo caso gli strumenti informatici (con riferimento in senso lato all'hardware, al s., ai sistemi informatici e alle reti telematiche) costituiscono l'oggetto dell'atto criminoso perpetrato dal soggetto autore del reato che non necessariamente dev'essere esperto d'informatica (basti pensare al lavoratore che per protesta danneggi un elaboratore e il relativo materiale informatico). Nel secondo caso, invece, l'informatica rappresenta il mezzo utilizzato dal soggetto autore dell'illecito per realizzare un ingiusto profitto con danno altrui. Nella previsione di quest'ipotesi l'autore del reato si profila come dotato di specifiche qualità tecniche e conoscenze del settore.
Recependo l'indirizzo comunitario che aveva delineato in una lista definita "minima" alcune fattispecie di reati informatici, il legislatore italiano a sua volta ha sanzionato come illeciti: il falso informatico (art. 3); l'accesso abusivo a un sistema informatico o telematico e la detenzione e la diffusione di chiavi di accesso o di programmi miranti a danneggiare o a interrompere un sistema informatico: si pensi ai cosiddetti ''virus informatici'', precedentemente esclusi dai meccanismi sanzionatori, e che sono previsti invece dalla nuova normativa (art. 4); l'intercettazione fraudolenta, l'impedimento o l'interruzione di comunicazioni relative a un sistema informatico o telematico (art. 6); la frode informatica (art. 10). Nella previsione di queste ipotesi l'abuso perpetrato da un qualificato operatore informatico costituisce una circostanza aggravante con una palese funzione deterrente nei confronti di un siffatto soggetto.
La nuova normativa contiene, inoltre, una precisa definizione di ''documento informatico'' che, agli effetti della tutela penale in essa prevista, viene considerato come "qualunque supporto informatico contenente dati o informazioni aventi efficacia probatoria o programmi specificatamente destinati ad elaborarli". Va rilevato, infine, come gli artt. 11, 12 e 13 della suddetta legge, modificando alcune disposizioni del codice di procedura penale, considerino gli strumenti informatici non soltanto dei potenziali mezzi per la perpetrazione dei reati a essi connessi, ma anche degli efficaci strumenti per la prevenzione e la repressione degli stessi reati.
Bibl.: A.A. Martino, Regime giuridico del software, Firenze 1988; R. Ristuccia, V. Zeno Zencovich, Il software nella dottrina e nella giurisprudenza, Padova 1990; I reati informatici. Computer security, a cura di C. Triberti, Milano 1990; S. Gatti, Software, in Enciclopedia del diritto, 42, Milano 1990, pp. 1208-13; G. Iudica, La formazione di contratti "a strappo" di licenza di software "pacchettizzato", in Silloge in onore di Giorgio Oppo, Padova 1992, vol. 2, pp. 161-72. Sulla nuova normativa: N. Cuomo, C. Triberti, Criminalità informatica: approvata la legge: Legge 23 dicembre 1993, n. 547. Il commento, in Il Corriere giuridico, 5 (1994), pp. 537-39.