Progetto Ingegneria del Software: MWI – MySql Weka Interface

Transcript

Progetto Ingegneria del Software: MWI – MySql Weka Interface
 Progetto Ingegneria del Software: MWI – MySql Weka Interface Matteo Rucco 082218 Matr. C o r s o d i L a u r e a M a g i s t r a l e i n C o m p u t e r S c i e n c e Sommario 1. Introduzione........................................................................................................................................3 2. Descrizione del problema e raccolta dei requisiti..................................................................4 2.1. Requisiti Funzionali.................................................................................................................................5 2.2. Requisiti Non Funzionali........................................................................................................................5 3. Analisi ....................................................................................................................................................6 3.1. Il dizionario dei termini: Gellish .........................................................................................................6 3.2. Alloy ..............................................................................................................................................................7 3.3. UML................................................................................................................................................................9 3.3.1. Use Case.....................................................................................................................................................................9 3.3.2. Activity-­‐Diagram ................................................................................................................................................12 4. Progettazione................................................................................................................................... 13 4.1. Class Diagram.......................................................................................................................................... 13 4.1.1. Associazione.........................................................................................................................................................14 4.1.2. Aggregazione........................................................................................................................................................14 4.1.3. Composizione ......................................................................................................................................................14 4.1.4. Ereditarietà...........................................................................................................................................................14 4.2. Sequence Diagram................................................................................................................................. 15 4.3. OCL.............................................................................................................................................................. 16 4.4. Reti di Petri.............................................................................................................................................. 17 5. Implementazione............................................................................................................................ 20 5.1. Dalla progettazione a Java : JML ....................................................................................................... 20 5.2. Test ............................................................................................................................................................. 22 5.2.1. JUnit .........................................................................................................................................................................23 6. Conclusioni........................................................................................................................................ 26 6.1. Fonti ........................................................................................................................................................... 28 6.2. Software di terze parti ......................................................................................................................... 28 Progetto Ingegneria del Software: MWI – MySql Weka Interface 3 1. Introduzione La vita quotidiana di ciascuno di noi è ormai dipendente da complessi sistemi informatici, comunemente ci troviamo a utilizzare sistemi che hanno come obiettivo quello di velocizzare o migliorare lo stile di vita: gli elettrodomestici hanno al loro interno piccoli computer che ci aiutano nella gestione domestica, la produzione industriale e la distribuzione sono completamente computerizzate, il sistema finanziario è lapalissianamente sotto il controllo di flussi resi automatici grazie all’introduzione dei computer che eseguono software ad -­‐ hoc. Affinché questi sistemi siano affidabili, è necessario progettarli con metodicità: l’ingegneria del software rappresenta quindi la disciplina che ha come obiettivo quello di garantire software di qualità. La difficoltà è aumentata dall’astrazione che ha il software per sua natura: è intangibile, non è governato da leggi fisiche. Con la crescita della produzione del software, si è reso necessario introdurre sistemi di formalizzazione del software, uno sviluppo non organizzato rendeva lento il rilascio del programma e spesso senza essere verificato nella totalità dei casi e il tutto comportava un incremento notevole di costi di produzione, gestione e manutenzione. Dal 1968 a oggi molto si è fatto: sono stati introdotti nuovi standard documentali, sono stati individuati e ormai rispettati all’unisono i passi principali che portano allo sviluppo e rilascio di software affidabile, ecc…. Solo grazie a questi miglioramenti siamo in grado di compiere scoperte uniche, mantenere attivi i contatti, ricevere informazioni costantemente, scrivere documenti che sono automaticamente corretti e anche giocare. Il presente documento, redatto come lavoro conclusivo del progetto MWI: MySql Weka Interface intende illustrare l’applicazione degli strumenti discussi durante il corso di Ingegneria del Software tenuto dal prof. Rosario Culmone e quindi non vuole essere una guida sostitutiva delle diapositive o di altre pubblicazioni. Il canovaccio sarà abbastanza simile alla programmazione del corso di IDS e potrà essere così riassunto: 1. Descrizione del problema e raccolta dei requisiti 2. Analisi 3. Progettazione 4. Implementazione 5. Test 2. Descrizione del problema e raccolta dei requisiti Nel contesto della ricerca sull’analisi dei dati avviata per conto del gruppo Loccioni, è stata riscontrata la necessità di realizzare un software in grado di estrapolare dei dati presenti in un database relazionale e riassumerli in un file dal formato ARFF Attribute-­Relation File Format da utilizzare con il software open source per il machine learning Weka prodotto dalla Waikato University. Il formato ARFF è un file di testo ASCII che descrive un elenco d’istanze che condividono un insieme di attributi. Oltre alla produzione del file, per aumentare l’interazione con l’utente finale (esperto di dominio) si è avvertita la necessità di produrre a monitor un plot (X-­‐Y) e una tabella riepilogativa dei dati estratti dalla base di dati. Poiché il software dovrà essere utilizzato in un contesto aziendale, quindi di produzione commerciale, questo dovrà garantire affidabilità, portabilità e velocità d’utilizzo. Considerando che Weka è stato interamente scritto in Java, è stato naturale codificare anche MWI con lo stesso linguaggio. La struttura del file ARFF è vincolata dalle specifiche imposte da Weka, mentre si è scelto di produrre i due pannelli contenenti rispettivamente il ResultSet della query sql eseguita sul database e il grafico in maniera indipendente l’uno dall’altro, questo per garantire all’utente di scegliere quale informazione conservare a monitor (entrambe o una sola delle due). Il grafico sarà comunque raggiungibile anche dopo la terminata esecuzione del programma, infatti, esso al momento della sua generazione sarà anche salvato come file d’immagine. Questa descrizione informale, può essere resa rigorosa adottando la notazione MoSCoW che consente per discernere i requisiti funzionali e quelli non funzionali. I primi ci indicano la parte funzionale, ossia a cosa serve e cosa deve fare il software mentre quelli non funzionali possono essere adoperati per descrivere, puntualizzare, proprietà del software che non sono indispensabili per il suo corretto funzionamento. Sintetizziamo quanto sopra utilizzando due tabelle: Progetto Ingegneria del Software: MWI – MySql Weka Interface 5 2.1.Requisiti Funzionali ID Descrizione MoSCoW 0 Il programma deve generare un file ARFF Must Have 1 Il programma deve salvare il grafico con formato Must Have immagine. 2 Il programma deve far vedere il grafico durante la Must Have sua esecuzione. 3 Il programma deve far vedere una tabella Must Have riassuntiva della query durante la sua esecuzione. Tabella 1 requisiti funzionali 2.2.Requisiti Non Funzionali ID Descrizione MoSCoW 0 Il programma dovrebbe generare a monitor due Must Have pannelli separati: uno per la tabella riassuntiva e uno per il grafico. 1 Il programma deve essere sviluppato in Java. Must Have 2 Il programma deve essere veloce Must Have 3 Ci dovrebbero essere due panel separati Should Have 4 Il programma dovrebbe essere personalizzabile con Should Have file XML esterni per la definizione dei parametri di connessione al database. Tabella 2: requisiti non funzionali Ricordiamo il significato delle etichette caratterizzanti il sistema MoSCoW: •
Must Have: sono requisiti che devono essere analizzati obbligatoriamente affinché la consegna del progetto risulti con successo. Se anche uno solo dei requisiti appartenente a questa categoria dovesse essere ignorato, allora il progetto fallirebbe. •
Should Have: requisiti importanti ma non fondamentali. Questi spesso a differenza dei “Must Have” sono requisiti che non sono ritenuti time-­‐critical. Possono essere riscontrati durante la seconda release del progetto. •
Could Have: sono requisiti solitamente necessari solo per aumentare la customer-­‐
satisfaction. •
Won’t Have: requisiti che non devono essere implementati (negazione di una funzione) particolarmente importanti ad esempio in software bancari (non si può accedere senza password). 3. Analisi 3.1.Il dizionario dei termini: Gellish Per evitare ambiguità nella stesura del progetto e soprattutto per evitare incomprensioni fra gli esperti di dominio (committente) e analisti, progettisti e programmatori è bene formulare un dizionario dei termini. Si è deciso di adottare Gellish come dizionario, esso ha al suo interno diversi termini che da un standard de-­facto sono diventati standard ISO. Oltre ad avere una struttura intellegibile un altro punto di forza di Gellish è rappresentato dall’immediatezza con cui si possono definire nuovi termini per mezzo di relazioni con altri già presenti. Per ogni termine e relazione è presente un codice univoco, questo consente anche di eseguire più rapidamente ricerche. Nell'esempio precedente, i concetti denominati 'torre' e 'città', così come i tipi (standard) di relazione sono selezionati con i loro UID dal Gellish English Dictionary. Ciò permette di formulare le domande utilizzando lo stesso linguaggio Gellish. Per consentire di esprimere le query e il linguaggio Gellish comprende termini standardizzati, come what, which, where e when. I progettisti, una volta individuati i termini principali potranno decidere se utilizzare un dizionario già pronto (quindi ad esempio quello di Gellish) o realizzarne uno personalizzato. Qualora si dovesse adottare la seconda soluzione, come nel presente documento, si suggerisce come buona pratica di mantenere una struttura non troppo dissimile dai dizionari noti, prevedendo così una possibile futura migrazione verso dizionari adottati da altre realtà. Seguendo uno schema di dizionario presentato nel corso di IDS, si conviene nel realizzare quanto segue: Progetto Ingegneria del Software: MWI – MySql Weka Interface 7 Termine Relazione Termine Algorithm Is used by Person Machine Learning Is a set of Algorithm Weka Is a set of Machine Learning Interface Is used by Person GUI Is a specialization of Interface Jtable Is a component of GUI ARFF Is a specialization of File ARFF Is used by WEKA Tabella 3 Esempio di dizionario personalizzato Nel compilare il dizionario si è scelto di non inserire le relazioni per i termini che si ha certezza che non abbiano interpretazioni univoche (file, person, ecc…)1. 3.2.Alloy I sistemi complessi possono essere analizzati ricorrendo al concetto di modello: esso può essere inteso come una rappresentazione astratta che si presta quindi ad essere più agevolmente analizzata rispetto alla forma iniziale del problema. Design and coding rappresentano due fasi distinte del processo di produzione del software e nella fase di disegno la formulazione del modello è necessaria per spiegare e valutare l’intero sistema. Alloy è un linguaggio, piuttosto semplice, basato sulla Logica del Primo Ordine FOL e creato allo scopo di assistere la progettazione di una grande varietà di sistemi software. Utilizzando Alloy si possono generare scenari con cui verificare i vincoli espressi dai requisiti. I domini di elementi sono specificati attraverso la parola riservata sig – signature – che può essere interpretata come l’analogo della classe nella programmazione ad oggetti. All’interno di ogni signature possono essere specificate le relazioni con elementi di altre signature o con suoi stessi elementi. Altra struttura essenziale è espressa dai fact – fatti – postulati che devono essere rispettati durante il checking del modello. I vincoli nel sistema sono invece realizzati 1 Per informazioni su Gellish: http://sourceforge.net/apps/trac/gellish/wiki attraverso i predicati pred. Alloy consente di utilizzare gli operatori matematici di confronto (o più genericamente relazionali), definire il numero di elementi – cardinalità – degli insiemi2. Figura 1 Esempio di modellazione con Alloy Nell’esempio di Figura 1, è riportato un estratto della modellazione del problema in esame, in dettaglio si possono riscontrare le definizioni delle signature principali, l’introduzione di alcuni fatti (ad esempio negano che nome utente e password siano li stessi o che nome utente e nome database siano uguali, ecc…) e di un predicato che agisce sulla cardinalità . Il risultato dell’esecuzione con Alloy Analyzer può essere sia testuale sia visivo: 2 Per la semantica e la sintassi http://alloy.mit.edu/alloy/documentation.html completa e aggiornata si invita il lettore a consultare il seguente: Progetto Ingegneria del Software: MWI – MySql Weka Interface 9 Figura 2 Esempio di run su predicato con Alloy Analyzer 3.3.UML Dal punto di vista di ingegnerizzare il processo di produzione di software di qualità, ed in particolare contemplando le peculiarità dei linguaggi orientati agli oggetti fu inventato il linguaggio UML, la cui sigla sta per Unified Modeling Language. L'UML è un metodo per descrivere l'architettura di un sistema in dettaglio. Adoperando una sorta di cianografia sarà possibile costruire o manutenere un sistema e assicurarsi che il sistema stesso si presterà senza troppe difficoltà a futuri cambiamenti dei requisiti. La forza dell'Unified Modeling Language consiste nel fatto che il processo di disegno del sistema può essere compiuta in modo tale che i clienti, gli analisti, i programmatori e chiunque altro sia coinvolto nel sistema di sviluppo possa capire ed esaminare in modo efficiente il sistema e prendere parte alla sua costruzione in modo attivo. L’UML si struttura di diversi tipi di diagrammi, qui saranno applicati solo alcuni di questi3 3.3.1. Use Case La modellazione dei casi d’uso è una forma più articolata di ingegneria dei requisiti. La modellazione dei casi d’uso prevede tipicamente i seguenti passi: •
Individuare un potenziale confine del sistema •
Individuare gli attori •
Individuare i casi d’uso: o Identificare il caso d’uso o Identificare le principali sequenze degli eventi 3 Per dettagli maggiori si invita a consultare il seguente: http://www.uml.org/ In dettaglio: •
Attori: i ruoli assunti dalle persone e dalle cose che usano il sistema •
Casi d’uso: quello che gli attori possono fare con il sistema •
Relazioni: relazioni significative tra gli attori e i casi d’uso •
Confine del sistema: un rettangolo disegnato intorno ai casi d’uso per indicare il confine del sistema oggetto del modello Oltre alla rappresentazione grafica che segue: Figura 3 Esempio di Use Case Possiamo riassumere le attività adoperando delle tabelle, ad esempio: Use Case : Database e Query ID : 1 Descrizione Sommaria: Connessione al Database ed esecuzione query SQL. Il dataset prodotto come output sarà utilizzato per realizzare il grafico, la produzione del file ARFF e la generazione del report a video Attore Unico (primario e secondario): Amministratore Pre-­‐Condizioni: 1. Il server per il database deve essere attivo 2. I driver per la connessione al database devono essere validi 3. Non ci devono essere altre query in esecuzione (accesso esclusivo) Flusso: 1. Use Case avviato al momento dell’esecuzione del software Progetto Ingegneria del Software: MWI – MySql Weka Interface 11 2. Si verifica la connessione al database 3. Si esegue la query di tipo Select 4. Si popola una struttura dati che verrà utilizzata per gli altri Use Case Post-­‐Condizioni: 1. La struttura dati deve essere disponibile per gli altri Use Case Flusso Alternativo: generazione avvisi di errore Use Case : ARFF ID : 2 Descrizione Sommaria: Se la struttura dati prodotta dall’Use Case ID=0 non è vuota, allora si procede alla generazione del file ASCII con formato ARFF che dovrà rispettare la struttura decisa dai produttori di Weka Attore Unico (primario e secondario): Amministratore Pre-­‐Condizioni: 1. La struttura dati deve essere disponibile e non deve essere vuota Flusso: 1. Si individuano il nome delle colonne che saranno utilizzati come nome dei parametri del file 2. Si individuano il numero di righe 3. Si esegue un loop sulle righe e sulle colonne per popolare una nuova struttura dati ad -­‐ hoc per il file ARFF 4. Si scrive il contenuto della struttura dati creata al punto precedente in un file Post-­‐Condizioni: 1. Generazione del file con struttura ed estensione ARFF Flusso Alternativo: generazione avvisi di errore Use Case : Grafico ID : 3 Descrizione Sommaria: Il dataset prodotto in ID=0 è utilizzato per la generazione di un grafico che sarà visualizzato a monitor e salvato su disco fisso Attore Unico (primario e secondario): Amministratore Pre-­‐Condizioni: 1. Il dataset deve essere stato popolato dalla query SQL Flusso: 1. Si estrapolano le colonne 1 e 4 dal dataset (relative a ID e valori di temperatura) 2. Si realizza e si salva il grafico 3. Il grafico è mostrato a schermo Post-­‐Condizioni: •
Generazione file di immagine contenente il grafico Flusso Alternativo: generazione avvisi di errore 3.3.2. Activity-­Diagram I diagrammi di attività possono essere interpretati come diagrammi di flusso che consentono di modellare un processo come un’attività costituita da un insieme di nodi connessi da archi. Questi diagrammi spesso sono chiamati, in letteratura, “diagrammi di flusso OO”. La loro semantica è stata rivista con la pubblicazione delle ultime versioni di UML (versione 2 in particolare) ed è fortemente basata sulle reti di Petri4. Esistono tre categorie di nodi5: 1. Nodi azione: rappresentano unità discrete di lavoro atomiche all’interno dell’attività; 2. Nodi controllo: controllano il flusso attraverso l’attività; 3. Nodi oggetto: rappresentano oggetti usati nell’attività. Gli archi rappresentano il flusso attraverso l’attività, possono essere suddivisi in due categorie: 4 Utili indicazioni al seguente: http://www.agilemodeling.com/style/activityDiagram.htm 5 Si suggerisce il seguente strumento online per disegnare i diagrammi: https://creately.com/ Progetto Ingegneria del Software: MWI – MySql Weka Interface 13 1. Flussi di controllo: rappresentano il flusso di controllo attraverso l’attività; 2. Flussi di oggetti: rappresentano il flusso di oggetti attraverso l’attività. Figura 4 Activity Diagram con costrutto condizionale e fork 4. Progettazione Terminate le fasi precedenti in cui sono stati raccolti ed analizzati i requisiti, si deve passare dal “che cosa fare” alla fase di “come fare”. La fase di progettazione serve a stabile come la realizzazione deve procedere. Sinteticamente possiamo affermare che l’input della progettazione è il documento di specifica e l’output sarà il documento di progetto che diventerà la guida per la codifica. Esistono diversi strumenti a supporto della progettazione, alcuni sono dettagliati dall’UML (per esempio: class diagram) altri invece sono strumenti autonomi quali OCL e Petri Net (questi ultimi possono essere talune volte adoperati anche in fase di analisi) 4.1.Class Diagram Rappresentano la struttura di un sistema. Sono usati durante la fase di analisi dei requisiti e il system design di un modello. È possibile definire diagrammi contenenti classi astratte e altri in cui compaiono istanze delle stesse con i relativi attributi specificati. Ogni nodo del grafo rappresenta una classe o un istanza con un nome (nel caso di un’istanza il nome è sottolineato) e contiene i suoi attributi e il suoi comportamenti (le operazioni che essa svolge). Ogni attributo ha un tipo e ogni operazione ha una firma. Le entità del grafo possono essere interconnesse tramite archi con freccia, senza freccia o tratteggiati ed avere le seguenti relazioni: 4.1.1. Associazione L’arco semplice rappresenta una associazione che può essere specificata anche da un testo, inoltre è possibile indicare le molteplicità: ad esempio un’entità X può essere associata ad una o più entità Y in tal caso avremo il seguente diagramma: Figura 5 Class Diagram: Associazione 4.1.2. Aggregazione E’ possibile rappresentare chi contiene cosa sotto forma di grafo (o albero) utilizzando la linea con il rombo terminatore come nella figura. Figura 6 Class Diagram: Aggregazione 4.1.3. Composizione Una particolare aggregazione che comporta l’esistenza di un’entità padre data un’entità figlio. In particolare: Figura 7 Class Diagram: Composizione 4.1.4. Ereditarietà Indica l’ereditarietà tra entità: la classe figlio eredità attributi e operazioni del padre semplificando il modello ed eliminando la ridondanza. Figura 8 Class Diagram: Ereditarietà Progetto Ingegneria del Software: MWI – MySql Weka Interface 15 Figura 9 Class Diagram per MWI La classe MyTable2 utilizza oggetti di altre classi, ad esempio adoperando un oggetto della classe XMLreader legge da un file XML i tre parametri necessari da passare ad un oggetto della classe MySQLAccess che stabilisce la connessione al database ed esegue la query sql. Il costruttore della classe MySQLAccess vuole tre parametri in input per stabilire la connessione con MySQL. Lo stereotipo “usa” sulla linea tratteggiata può essere omesso, il suo significato è univoco. L’elemento grafico sopra MySQLAccess è invece un commento. 4.2.Sequence Diagram I diagrammi di sequenza mostrano lo scambio di messaggi (cioè la chiamata ai metodi) tra diversi oggetti in una situazione temporale precisa. Gli oggetti sono istanze di classi. I diagrammi di sequenza mettono particolare enfasi sull'ordine temporale con cui i messaggi sono inviati agli oggetti. Nei diagrammi di sequenza gli oggetti sono rappresentati con linee verticali tratteggiate, con il nome dell'oggetto in cima. Anche l'asse temporale è verticale, e aumenta andando in giù, in modo che i messaggi sono inviati da un oggetto all'altro nella forma di frecce con l'operazione e il nome del parametro. Se il progetto è ben strutturato, ci deve essere corrispondenza fra i blocchi dell’activity diagram e il sequence diagram. Il diagramma permette di identificare puntualmente il ruolo di ciascun attore e di descrivere il flusso prodotto dalle sue azioni. Ci sono differenze sostanziali fra il sequence diagram introdotto con l’UML 2 con quello del precedente UML 1. La nuova versione consente di rappresentare i costrutti decisionali, i cicli o esecuzione in parallelo: alt, loop e par rispettivamente6. Figura 10 Esempio di diagramma di sequenza (Sequence Diagram) – il diagramma è parziale I rettangoli con sfondo verde indicano gli oggetti delle varie classi che sono utilizzati dal metodo main della classe MyTable2. Lungo le frecce orizzontali tratteggiate possiamo riscontrare l’istanza dei vari oggetti mentre sulle linee dense vi è la chiamata dei vari metodi. 4.3.OCL I linguaggi formali permettono di definire un’interpretazione univoca di una dichiarazione, a differenza dei linguaggi naturali che spesso introducono ambiguità. OCL – Object Constraint Language – è il linguaggio formale che affianca la modellazione di UML per risolvere le ambiguità che i soli diagrammi potrebbero generare. I primi modelli formali quali Z e Syntropy, prevedevano l’utilizzo della notazione matematica, questo sicuramente garantiva di risolvere le ambiguità pur tuttavia rendeva il suo utilizzo confinato solo a una nicchia di 6 Per il disegno di sequence diagram: http://www.websequencediagrams.com/ Progetto Ingegneria del Software: MWI – MySql Weka Interface 17 utenti. Il linguaggio OCL è stato pensato proprio per estendere e superare questi limiti, la sua sintassi è stata pensata per essere sia formale che semplice. Taluni autori, Warner ad esempio, affermano che la sintassi di OCL si possa capire in pochi minuti di studio. Probabilmente tutto ciò è vero se si pensa che le industrie ormai ne fanno un impiego diffuso. Le parole maggiormente utilizzate sono context, pre, post e inv. Si può facilmente intuire che queste servono a definire il contesto in esame, le pre-­‐condizioni che devono essere verificate (eventualmente facendo riferimento a frasi complesse, quindi condizioni che devono agire su più attributi) e le post condizioni (ciò che si deve verificare dopo le pre-­‐condizioni) e le invarianti, ossia espressioni che devono essere sempre vere durante l’esecuzione dell’applicazione. Alcune espressioni OCL che potrebbero essere utilizzate per modellare MWI sono: context MySQLAccess :: MySQLAccess( localhost : String, nomeDB: String, nomeUtente : String, pwdUtente : String) inv: localhost != null nomeDB != null nomeUtente != null pwdUtente != nulla nomeUtente != pwdUtente Tabella 4 I esempio di OCL In questo frammento di codice OCL, si specifica il “contesto” e si impone una invarianza, ossia una condizione che deve essere sempre vera: i valori dei parametri non devono essere nulli e il nome utente deve essere diverso dalla password. context MySQLAccess :: connesso : Boolean init: false Tabella 5 II esempio di OCL Con questo tipo di istruzione OCL si può definire il valore iniziale che deve avere un attributo particolare. 4.4.Reti di Petri Sono uno strumento per la modellizzazione di processi ed in particolare per la modellizzazione delle comunicazioni e delle interazioni fra processi concorrenti. Quando si avverte di descrivere un processo con sottoprocessi, si scopre di sovente che ci sono alcuni sottoprocessi che devono essere eseguiti parallelamente e soprattutto in maniera indipendente: potrebbe accadere che un determinato passaggio o una certa fase del processo non possa verificarsi o non possa essere attivata fintanto che altre fasi o attività non sono concluse o fino al verificarsi di determinate condizioni. Queste situazioni non possono essere descritte attraverso un diagramma di flusso che per sua natura è pensato per descrivere evoluzioni sequenziali. Infatti, in un diagramma di flusso le attività sono rigidamente serializzate: due rami distinti di un diagramma di flusso non vengono mai “percorsi” contemporaneamente, ma rappresentano due scelte decise secondo un criterio rigidamente deterministico dipendente dall’esito della valutazione di una espressione booleana. Con le Reti di Petri questo limite (la serializzazione degli step del procedimento) viene superato, ma viene anche introdotto un formalismo grafico e semantico che permette di aggiungere una “dimensione” ulteriore alle Reti di Petri rispetto ai diagrammi di flusso. Le RdP, infatti, non solo permettono di rappresentare e di descrivere globalmente un processo, ma consentono anche di seguirne l’evoluzione permettendo di visualizzare lo stato in cui si trova in un certo istante la rete. Una Rete di Petri è un grafo che consiste di posti, transizioni ed archi che li collegano; gli archi di input collegano i posti con le transizioni, mentre gli archi di output collegano le transizioni con i posti. Possiamo dire che una Rete di Petri evolve passando attraverso una serie di stati; si conferisce uno stato a una Rete di Petri mediante una marcatura che consiste nell’assegnamento di un numero naturale a ogni posto. Graficamente, questo si traduce nell’inserimento in ogni posto di un numero equivalente di token. I token indicano lo stato di avanzamento delle operazioni descritte nei passi del processo. Possiamo modellare con le RdP sia esperienze di vita quotidiana (esempio canonico: preparazione di una ricetta) sia problemi più complessi e/o astratti quale quello in esame nel presente documento7. 7 Oltre al materiale fornito nel corso, può http://www.mat.uniroma3.it/users/liverani/doc/appunti_reti_di_petri.pdf tornare utile visionare il seguente: Progetto Ingegneria del Software: MWI – MySql Weka Interface 19 Figura 11 Esempio di marcatura della Petri Net per MWI 5. Implementazione 5.1.Dalla progettazione a Java : JML Java Modelling Language (JML) e' un linguaggio di specifica che permette di definire astrazioni procedurali. Le specifiche vengono aggiunte all'interno del codice sorgente Java, tramite commenti dotati di una speciale sintassi che precedono il metodo interessato. Questo significa che il codice JML non viene letto dal compilatore Java, ma solo dagli strumenti di JML. Adoperando JML i fatti introdotti con Alloy e tradotti in specifiche per OCL diventano dei vincoli rigorosi direttamente all’interno del codice, ad esempio si può imporre che i metodi accettino e ritornino un certo tipo ben specificato di parametro. Questo strumento che di fatto è coercitivo, permette di appaltare lo sviluppo del codice anche a gruppi esterni, sarà JML a verificare costantemente la corretta implementazione, quindi JML assume il duplice ruolo sia di strumento documentale che di strumento di vincolo direttamente nel codice. Il codice compilato non sarà sporcato da codice JML, questo perché esso apparirà come un commento nella forma: /* @ statement JML @*/. Le principali direttive di JML sono: •
requires: definisce una pre-­‐condizione sul metodo che segue •
ensures: definisce una post-­‐condizione sul metodo che segue •
signals: definisce una condizione in base alla quale deve essere lanciata una eccezione dal metodo che segue •
assignable: definisce di quali campi è consentito l'assegnamento dal metodo che segue •
pure: dichiara che il metodo che segue non ha effetti collaterali (è un'abbreviazione di assignable \nothing) •
invariant: definisce una proprietà invariante della classe. •
also: dichiara che un metodo deve ereditare le condizioni dalla sua superclasse. •
assert: definisce una asserzione JML. Nel seguito è illustrato un esempio di applicazione di JML al codice Java del progetto MWI8. 8 http://www.ibm.com/developerworks/java/library/j-jml/index.html Progetto Ingegneria del Software: MWI – MySql Weka Interface 21 Figura 12 I Esempio di JML Figura 13 II Esempio di JML con gestione del segnale d’errore 5.2.Test L’obiettivo di questa fase non deve essere quello di far vedere che il software non contiene errori, bensì di trovarne il maggior numero possibile. Infatti per grandi programmi è utopistico aspettarsi che il codice venga prodotto senza errori. Per raggiungere questo scopo non è opportuno far testare il codice allo stesso team che lo ha prodotto: si assegna di solito un team specifico per il test. La fase si esegue a vari livelli e consiste in operazioni distinte. •
Test di unità. Un’unità è il più piccolo blocco di software che ha senso collaudare, ad esempio una singola funzione di basso livello viene verificata come un’entità a se stante. •
Test di modulo. Un modulo è un insieme di unità interdipendenti. •
Test di sottosistema. Un sottosistema è un aggregato significativo di moduli spesso progettati da team diversi, e quindi vi possono essere problemi di interfaccia. •
Test di sistema o integrazione. Si tratta del test del prodotto completo. •
α-­‐test. Se il sistema è sviluppato per un unico cliente, viene portato nel suo ambiente finale e collaudato con i dati sui quali dovrà normalmente operare. •
β-­‐test. Se il sistema viene distribuito ad una comunità di utenti, viene dato in prova a più utenti, che lo utilizzano e forniscono al produttore le loro osservazioni ed il rilevamento degli errori riscontrati. •
Benchmark. Il sistema viene testato su dati standardizzati e di pubblico dominio per il confronto con altri prodotti equivalenti già presenti sul mercato. Può venire richiesto per contratto. •
Stress testing. Si verifica come si comporta il sistema quando è sovraccarico di lavoro, portandolo al limite. Questo test sotto sforzo permette di causare un errore (da stress) e verificare che il sistema fallisca in un modo accettabile (fail-­‐soft). Testing e debugging sono due concetti diversi. Il Testing serve a rilevare la presenza di un errore. Il Debugging consiste nella localizzazione dell’errore, della sua analisi e della sua correzione. Terminato il debugging si fa seguire il test di regressione: si verifica il comportamento del modulo che è stato corretto nei confronti dei moduli con i quali coopera, assicurandosi così che la correzione dell’errore non ne abbia introdotti di nuovi9. 9ftp://docenti.ing.units.it/arc_stud/Sbroiavacca/SistemiInformativi1_06/Ingegneria%20del%20Software%20%20Test%20e%20Collaudo.pdf Progetto Ingegneria del Software: MWI – MySql Weka Interface 23 5.2.1. JUnit JUnit è un framework open source per effettuare il testing in modo organizzato e semplice. Come si può intuire dalla “J” è un framework scritto in Java e quindi gli esempi proposti saranno tutti in Java. Comunque JUnit è una istanza della classe xUnit, cioè esistono conversioni per un gran numero di linguaggi, fra i quali anche C#, C++ e Visual Basic. È stato sviluppato da Erich Gamma e Kent Beck ed è scaricabile da http://www.junit.org. JUnit è nato per la scrittura di test unitari. I test unitari sono dei test che vanno a verificare la correttezza direttamente del codice, in ogni sua piccola parte. Questi test, che hanno avuto una grande diffusione all’interno della extreme programming, vanno scritti ed eseguiti dal programmatore stesso per ogni porzione di codice da lui sviluppata. I test funzionali, invece, sono dei test che vanno a verificare che il software nella sua completezza funzioni correttamente. Questi test trattano il sistema come se fosse una scatola nera alla quale danno degli input e verificano la correttezza degli output. Devono essere ideati ed eseguiti da personale che non ha partecipato alla costruzione del software. Un’alternativa all’uso dei test unitari è sicuramente l’inserimento nel codice prodotto di comandi il cui unico scopo è di effettuare debugging. La soluzione più semplice per questo scopo è sicuramente l’inserimento di comandi tipo system.out.println atti a stampare variabili critiche per poterle analizzare. Questa soluzione presenta però almeno due grossi inconvenienti: innanzitutto è necessario andare a modificare il codice sorgente ogni qualvolta si voglia tracciare una nuova variabile, in secondo luogo è necessario analizzare l’output alla ricerca di eventuali errori manualmente e ad ogni esecuzione. Inoltre va sottolineato che per distribuire il progetto è necessario eliminare tutti i comandi inseriti nel codice per il testing e, soprattutto, qualora si debba apportare ulteriori modifiche ai sorgenti e si voglia testarli nuovamente è necessario reinserire tutti i comandi precedentemente cancellati. Se per programmi brevi e semplici può anche essere una soluzione valida, sicuramente per progetti di grosse dimensioni diviene difficile e laboriosa tale gestione. JUnit, invece, permette una maggiore strutturazione dei test, facilità nell’inclusione di nuovi test o nella eliminazione di altri e soprattutto un’immediata lettura dei risultati. Infatti, come vedremo, la risposta dopo l’esecuzione di una batteria di test in caso di successo è un semplicissimo OK. Questo velocizza non di poco l’esecuzione e la verifica dei test. Inoltre, strutturando correttamente le classi adibite al testing, sarà possibile distribuire il codice prodotto privato del codice di testing senza apportare alcuna modifica e, se in un secondo momento si dovranno ripetere i test o aggiungerne di altri, non sarà necessario riscriverli ma semplicemente rieseguirli. Pertanto, sebbene il lavoro richiesto per la stesura dei test sfruttando JUnit possa sembrare eccessivo ad una prima analisi, è assolutamente consigliato ricorrere a questa metodologia in quanto garantisce il corretto funzionamento del codice prodotto. Forniamo un esempio di Junit su una classe con struttura funzionale molto semplice: Figura 14 Esempio di classe a cui sarà applicato JUnit La classe MathOp oltre al costruttore, ha due metodi che accettano due interi e ritornano rispettivamente la loro somma o sottrazione. Parallelamente a questa classe, ne scriviamo una per i test case Per indicare a JUnit quali sono i metodi che effettuano i test è necessario contraddistinguerli con l’annotazione @Test. In questo modo JUnit riconoscerà i metodi che contengono le asserzioni e li tratterà di conseguenza: Figura 15 Classe ombra per l'applicazione di JUnit Con JUnit è possibile effettuare diversi tipo di test (con asserzioni diverse). Al momento dell’esecuzione, un test si considera superato se tutte le condizioni specificate risultano verificate. Progetto Ingegneria del Software: MWI – MySql Weka Interface 25 •
assertEquals(expected, actual), assertArrayEquals(expected, actual) : richiede che il valore ‘expected’ sia uguale a ‘actual’ •
assertTrue(cond): richiede che ‘cond’ abbia come valore: ‘true’ •
assertFalse(cond): richiede che ‘cond’ abbia come valore ‘false’ •
assertNull(obj): richiede che ‘obj’ sia un riferimento nullo •
assertNotNull(obj): richiede che ‘obj’ sia un riferimento non nullo Nell’esempio precedente, in ognuno dei due test case è stato istanziato un oggetto MathOp. JUnit mette a disposizione degli sviluppatori una funzionalità per eseguire delle istruzioni prima che vengano eseguiti i test. Il metodo setUp() ha un’annotazione @Before che serve ad indicare a JUnit che il metodo va eseguito prima dell’esecuzione dei test case. In questo modo, il codice per inizializzare oggetti o risorse (ad esempio una connessione al DBMS) è concentrato in un solo punto della classe di test. Analogamente a @Before, l’annotazione @After indica a JUnit di eseguire il metodo dopo l’esecuzione dei test case. Figura 16 Seconda versione della classe ombra 6. Conclusioni L’applicazione di tutti gli strumenti introdotti nel presente documento ha consentito sia di risolvere l’obiettivo prefissato ma soprattutto di acquisire maggiore confidenza con la teoria e con il ciclo di vita che ha portato al rilascio di un software di qualità. Alcune verifiche di funzionamento, ci permettono di stabilire anche il tempo necessario per l’esecuzione del software: Configurazione utilizzata – MacBook Pro 2.4 GHz Intel Core 2 Duo – RAM 8 GB 1067 MHz DDR3 Numeri di righe presenti nella tabella del database: 80 Tempo totale per connettersi al database MySQL, eseguire la Select, popolare la Jtable, salvare il file ARFF, produrre il grafico e generare il file di immagine: 2.98s Figura 17 Grafico della temperatura Figura 18 JTable popolata da MySQL Progetto Ingegneria del Software: MWI – MySql Weka Interface 27 Figura 19 Processing del file ARFF in WEKA Figura 20 File ARFF 6.1. Fonti Oltre al materiale del corso e i siti inseriti nelle note a piè di pagina, sono stati consultati i seguenti testi: Sommerville I. Ingegneria del software. VIII edizione. Pearson Addison -­‐ Wesley, 2007 Arlow J., Neustadt I. UML 2 e Unified Process: analisi e progettazione Object-­‐Oriented. II edizione. McGraw-­‐Hill, Milano, 2006 6.2.Software di terze parti I seguenti software sono stati necessari per la progettazione e l’implementazione del progetto: •
Alloy V4 •
Pipe V4 •
ArgoUML •
Eclipse con plugin per Junit