Università degli Studi di Milano Bicocca – Laurea Magistrale in Informatica Corso di Evoluzione Sistemi Software e Reverse Engineering 2008/2009 – Prof.ssa Arcelli Object Oriented Reenginnering Pattern Tests:Your Life Insurance! Migration Strategies Carella Carmine Faustinoni Fabrizio Falco Giuseppe Passoni Alberto Riferimenti: Object Oriented Reenginnering Pattern - S.Demeyer, S.Ducasse, O.Nierstrasz, 2008. 1 Tests: Your Life Insurance! Il tema principale del cluster è: l’utilizzo di strategie di testing nel contesto della reingegnerizzazione per ridurre i rischi del processo di cambiamento di un sistema legacy critico per il business aziendale. N.B: le strategie di testing presentate non sono le uniche possibili, ma quelle più rilevanti nel caso di un progetto di reengineering. 2 Pattern che compongono il cluster e loro relazioni: Tests: You Life Insurance! 3 Write Test to Enable Evolution OBIETTIVO: proteggere il valore del legacy system attraverso un testing sistematico. PROBLEMA: minimizzare i rischi in un processo di reengineering. Modificare un legacy è rischioso per il business. Quali Rischi? – Non soddisfare l’obiettivo del reengineering; (miglioramento legacy system evoluzione) – Introdurre ulteriore complessità nel sistema; – Compromettere le funzionalità critiche per il business; – Intraprendere una strada sbagliata: troppi sforzi per un task che non è quello designato; – Aumentare ulteriormente i costi di mantenimento. Tests: You Life Insurance! 4 Write Test to Enable Evolution Problema Difficile perché: • La valutazione dei cambiamenti non sempre è possibile • Test non sempre è applicabile – componenti non comprese perché non documentate test progettato male – Dipendenze nascoste, destabilizzano il sistema. Problema risolvibile – Sistema in esecuzione e si determina cosa funziona e non funziona – Sono note le parti del sistema stabili e quelle soggette a cambiamenti Soluzione – Un processo di testing basato su test ben progettati. (Well-designed test) Tests: You Life Insurance! 5 Well-Designed test – proprietà – Automatico: test eseguiti senza intervento umano. Test pienamente automatici. – Persistente: un test, per essere automatico deve essere memorizzato. Memorizzare i dati del test, le azioni da eseguire e il risultato atteso. • Documentazione del sistema; • Soggetto a controllo delle versioni, come altro codice; – Ripetibile: dopo ogni implementazione di un cambiamento il test deve essere rieseguito. Data una nuova funzionalità deve esser possibile aggiungere facilmente nuovi test tra quelli esistenti (test suite). – Unit testing: i test dovrebbero essere associati a componenti software atomiche , per identificare chiaramente quali parti testano e ridurre la complessità del test. – Indipendente: minimizzare le dipendenze con gli altri test per evitare “effetto a cascata”. Il numero di test falliti deve essere un indicatore del numero di problemi rilevati. Tests: You Life Insurance! 6 Write Test to Enable Evolution Vantaggi: – I test aumentano la fiducia nel sistema e favoriscono cambiamenti sicuri permettendo l’evoluzione. – Documenti di test come artifacts di un sistema. Descrizione del sistema sempre aggiornata, rispetto alla documentazione scritta. – Framework di supporto esistono per tutti i principali linguaggi object oriented (Smalltalk, Java C++). Svantaggi: – – – – Allocare risorse umane per scrivere i test I test dimostrano solo la presenza di difetti, non li risolvono. È impossibile coprire con i test tutti gli aspetti di un sistema legacy Test progettati male: il test viene eseguito si pensa tutto va bene, ma in realtà non sta testando il comportamento desiderato. Tests: You Life Insurance! 7 Write Test to Enable Evolution Difficoltà: – – – – Troppi approcci di testing esistenti. Scelta dell’approccio più adatto. Legacy system grandi e non documentati testing proibitivo Management è restio nell’investire nel testing. Convincere gli sviluppatori ad adottare il testing: mostrare come il testing non solo velocizza lo sviluppo ma anche l’attività di mantenimento – Il testing può essere un attività noiosa: utilizzo del toll di supporto più adatto. Tests: You Life Insurance! 8 Write Test to Enable Evolution Conclusioni: • I test rappresentano una forma tangibile di fiducia nel sistema, perché permettono di verificare che il sistema sia corretto e possono essere eseguiti quando si vuole per verificarne la consistenza. • I test sono la base per il reengineering. Attività di Mantenimento documentazione Fiducia nel sistema Evoluzione Architetturale Riduzione dei rischi Fiducia nei cambiamenti al sistema Tests Automatici Tests: You Life Insurance! 9 Write Test to Enable Evolution Relazioni con altri pattern: – – – – Always have a running version Migrate system incrementally Grow your test base incrementally Test the interface, not the implementation Tests: You Life Insurance! 10 Grow Your Test Base Incrementally OBIETTIVO: bilanciare i costi e i benefici dei test, introducendoli incrementalmente solo quando necessario. Tests: You Life Insurance! 11 Grow Your Test Base Incrementally Problematiche: – Progettazione dei casi di test occupa una notevole quantità di tempo quando fermarmi nel costruire casi di test? – Impossibile testare tutte le parti che compongono un legacy system data la loro grandezza e complessità – I programmatori che hanno realizzato il sw non sono più reperibili e quindi le conoscenze del legacy sono limitate. Soluzione: – Introdurre i test incrementalmente, solo per quelle parti del sistema su cui stiamo lavorando Tests: You Life Insurance! 12 Grow Your Test Base Incrementally Suggerimenti: – Sviluppare i casi di test nel seguente ordine: 1. 2. 3. Inizialmente solo per le componenti più critiche e con priorità più alta. Per le nuove funzionalità create durante la fase di reengineering. Per le parti che presentano bug importanti. – Se si ha una storia dei vecchi bug risolti, usare i vecchi Test bug come punto di partenza. – Testare le interfacce e non l’implementazione, iniziando dalle grandi gerarchie di astrazione e, se avanza tempo, testare singolarmente le parti. Tests: You Life Insurance! 13 Grow Your Test Base Incrementally Vantaggi: 1. Risparmi del tempo (in quanto si sviluppano solo i test necessari). 2. Costruzione di test per le parti più critiche del sistema. 3. Agevolazione dello sviluppo di funzionalità future e del mantenimento. Svantaggi: – – Errori nell’individuazione degli aspetti critici del sistema tempo e risorse sprecate. I test possono dare troppa fiducia in quanto possono ancora nascondersi bug importanti nel codice. Tests: You Life Insurance! 14 1. Individuare il sottosistema da modificare (ABC) 2. Introdurre i test solo per il sottosistema ABC e per la componente B 3. Applicare i test alla nuova componente B Tests: You Life Insurance! 15 Grow Your Test Base Incrementally CONCLUSIONI: • Una strategia di test incrementale consente di iniziare il processo di reengineering prima di aver sviluppato tutti i test. • Minimo investimento di risorse nella fase di test in quanto questa fase è concentrata solo su quelle parti che si intendono modificare e non su tutto il sistema. Tests: You Life Insurance! 16 Use a testing framework OBIETTIVO: Incoraggiare gli sviluppatori a scrivere ed utilizzare i test di regressione, fornendo un framework che ne renda facile lo sviluppo, l’organizzazione l’esecuzione. e PROBLEMA – Come incoraggiare il team a fare testing? Problema Difficoltoso : - i test sono noiosi da creare; - richiedono la creazione di dati ad-hoc per essere effettuati; - è difficile capire la differenza tra un test fallito ed un unexpected error. Tests: You Life Insurance! 17 Use a testing framework LA SOLUZIONE E’ FATTIBILE: - I test (la maggior parte) seguono lo stesso pattern CREAZIONE DATI DI PROVA ESECUZIONE DI ALCUNE AZIONI VERIFICA ESITO - l’infrastruttura per eseguire i test è semplice QUINDI… Utilizzare un framework di testing che consenta di comporre una test suite a partire da test case specifici Tests: You Life Insurance! 18 Use a testing framework POSSIBILE PROBLEMA: - Non esiste un framework di test per il linguaggio che si sta utilizzando NIENTE PAURA! Combinare le informazioni che si possiedono in accordo con i seguenti principi: - L’utente fornirà casi prova utilizzabili come test e fornirà asserzioni sui risultati; - Il framework fornisce un feedback in caso di successo insuccesso del test INDICA PRECISAMENTE IL TEST CHE E’ FALLITO GLI ERRORI DEVONO ESSERE COLLOCATI IN UN REPORT - Il framework consente la creazione di test suite Tests: You Life Insurance! 19 Use a testing framework PRO: Un framework per i test semplifica la formulazione dei test invoglia i programmatori ad effettuarli. ed CONS: La fase di test richiede impegno, disciplina e supporto; E’ difficoltoso convincere il team dell’utilità del testing; E’ complicato inserire la fase di test all’interno del processo di sviluppo di un team che non l’ha mai considerata. Tests: You Life Insurance! 20 Use a testing framework ESEMPI: Junit (test framework for Java) - I test sono definiti come sottoclassi di TestCase - Utente deve definire i metodi setUp(), runTest() e tearDown() - Gli errori sono gestiti e segnalati mediante l’utilizzo della classe TestResult - TestCase fornisce metodi standard come assertEquals e asserdFails - I test possono essere inseriti all’interno di una TestSuite ESISTONO FRAMEWORK DI TEST SPECIFICI PER OGNI TIPO DI LINGUAGGIO: Ada, ANT, C, C++, Delphi, .Net (all languages), Eiffel, Forte 4GL, GemStone/S, Jade, JUnit Java, JavaScript, k language (ksql, from kbd), Objective C, Open Road (CA), Oracle, PalmUnit, Perl, PhpUnit, PowerBuilder, Python, Rebol, ‘Ruby, Smalltalk, Visual Objects and UVisual Basic. Tests: You Life Insurance! 21 Test the Interface, Not the Implementation OBIETTIVO: costruire test riusabili che non si focalizzino sui dettagli di implementazione, ma piuttosto su comportamenti esterni, per sopravvivere ai cambiamenti del sistema PROBLEMA: Sviluppare test che siano resistenti nel tempo ai cambiamenti della componente a cui sono legati. Problema difficile perché: • mentre evolve, il legacy system deve continuare a supportare il processo di business; • non si può perdere troppo tempo nella scrittura dei test; • non impiegare troppe energie per scrivere test che diventeranno presto obsoleti. Tests: You Life Insurance! 22 Test the Interface, Not the Implementation Problema risolvibile: – Le interfacce dei componenti dicono cosa deve esser testato – Le interfecce tendono a essere più stabili dell’implementazione. Soluzione: – Sviluppare test di tipo black-box che sfruttano le interfacce pubbliche delle componenti. – Costruire la soluzione: • Come dati di test utilizzare valori estremi (minimo e massimo); • Se ci sono molte componenti fine-grained utilizzare una strategia top-down per sviluppare i test; • Se si sta modificando una funzionalità ben precisa utilizzare una strategia bottom-up per testarla. Tests: You Life Insurance! 23 Test the Interface, Not the Implementation Vantaggi: – Se l’implementazione cambia è poco probabile che la sua interfaccia subisca modifiche test sull’interfaccia è più riusabile; – Black-box tests possono essere usati per più implementazioni della stessa interfaccia; – I test sulle interfacce sono più semplici da realizzare; – Evita di scrivere i test troppo presto; Svantaggi: – I Black-box test non coprono tutto il codice; – Se l’interfaccia cambia, bisogna modificare il test; – La classe non fornisce la giusta interfaccia per l’applicazione del black-box test, allora altre strategie di testing (white-box testing). Tests: You Life Insurance! 24 Test the Interface, Not the Implementation Conclusioni: – Le interfacce di un componente, sono una conseguenza della sua interazione con altre componenti; il black-box test può essere utile nel verificare le principali interazioni di un sistema – Black-box test hanno maggiori probabilità di sopravvivere ai cambiamenti del sistema, perché le interfacce tendono ad essere più stabili. Relazioni con altri pattern: – Record business rule as tests. Tests: You Life Insurance! 25 Record Business Rules as Tests OBIETTIVO: Mantenere il sistema al passo con le regole di business da esso implementate codificandole come Test. Tests: You Life Insurance! 26 Record Business Rules as Tests Problematiche: • La documentazione spesso non contiene i dati relativi ai piani business • Regole business spesso sono implicite nel codice • Il cambiamento degli sviluppatori provoca l’aumento dei rischi • Cambiamento per fattori esterni • Risoluzione problematica semplice poiché le regole business seguono delle linee guida Tests: You Life Insurance! 27 Record Business Rules as Tests Soluzione: • Scrivere test eseguibili che registrano gli affari come casi di test. • Gli sviluppatori scrivono i test funzionali • I clienti scrivono i test di integrazione Tests: You Life Insurance! 28 Record Business Rules as Tests Vantaggi: • Regole esplicite, riduzione dipendenza umana • Prima di effettuare la reingegnerizzazione del legacy system si devono registrare le regole business • Permette l’evoluzione delle regole business: aggiunta di nuove features e test di regressione per verificare la loro correttezza Tests: You Life Insurance! 29 Record Business Rules as Tests Svantaggi: • I test codificano solo eventi concreti • La logica business prevede molti casi, ma non tutti vengono trattati • Registrare business rules non significa estrarre business rules. L’estrazione con la corrente tecnologia è ancora un sogno. • Registrare business rules è difficile se cambia il team Tests: You Life Insurance! 30 Record Business Rules as Tests Conclusioni: • I test sono un buon metodo per documentare ciò che il sistema fa. • Documentando i business rules come test, posso garantire la descrizione di esso durante l’implementazione Tests: You Life Insurance! 31 Write Test To Understand Obiettivo Registrazione della comprensione di parte del codice sotto forma di test eseguibili, in modo da essere utili quando si modificherà il sistema in futuro Tests: You Life Insurance! 32 Write Test To Understand Problematiche • • • • Codice non sempre comprensibile Ipotesi su quello che il codice fa e validazione di tali ipotesi Specificare il comportamento del sistema Documentazione obsoleta appena si cambia il codice Tests: You Life Insurance! 33 Write Test To Understand Soluzione • Codificare ipotesi e conclusioni come test eseguibili Tests: You Life Insurance! 34 Write Test To Understand Vantaggi • • • • • I test aiutano la comprensione I test offrono specifiche precise di certi aspetti del sistema I test sono applicati a diversi livelli di comprensione I test sviluppati aiuteranno il futuro reengineering Maggiore precisione nella creazione e uso dell’oggetto Tests: You Life Insurance! 35 Write Test To Understand Svantaggi • Scrivere test comporta la perdita di tempo • Oggetti testati non hanno un’astrazione • Non va bene per processi concorrenti Tests: You Life Insurance! 36 Write Test To Understand Conclusioni • Per scrivere test automatici bisogna partite dal sistema preso in considerazione e capirlo • Registrazione per settare il piano per una futura reingegnerizzazione Tests: You Life Insurance! 37 Migration Strategies Migration Strategies 38 Migration Strategies Introduzione Dopo i test la reingegnerizzazione è a buon punto, si ha una buona conoscenza del sistema legacy e si sono scritti i test che iniziano la fase di evoluzione. Domande • Siamo sicuri che il nuovo sistema sarà accettato? • Come migrare verso il nuovo sistema nonostante quello vecchio sia ancora in uso? • Si può testare il nuovo sistema prima che sia pronto? Migration Strategies 39 Migration Strategies Punti chiave: • • • • Migrazione Big-bang rischiosa Troppe modifiche creano confusione negli utenti Feedback Gli utenti devono fare il loro lavoro, ma non vogliono essere distratti da soluzioni incomplete • Data legacy devono rimanere intatti Panoramica Il reengineering non è sufficiente, bisogna introdurre la migrazione graduale verso un nuovo sistema in modo da essere indolore agli utenti. Migration Strategies 40 Migration Strategies Migration Strategies 41 Involve The User System • Obiettivo: massimizzare il numero di cambiamenti coinvolgendo l'utente a ogni step Migration Strategies 42 Involve The User System Problematiche: • I sistemi sono vecchi. Gli utenti vogliono sapere come funziona e come aggirare i problemi. • La gente odia il dover imparare qualcosa di nuovo a meno che non sia qualcosa di semplice • La percezione dell'utente di ciò che è necessario per migliorare un sistema. • Gli utenti possono avere difficoltà a valutare un documento di progettazione. • E‘ difficile essere entusiasti di un nuovo sistema che non è pronto per l'uso. Migration Strategies 43 Involve The User System Soluzione: Coinvolgere direttamente gli utenti e tenerli aggiornati sul sistema. Passi: • • • • chiedere agli utenti le priorità. dividere le priorità in fasi. utenti e sviluppatori si devono tenere in contatto. avere dei feedback sulle versioni intermedie. Migration Strategies 44 Involve The User System Vantaggi: • I requisiti devono essere aggiornati e validati spesso, per andare verso il risultato sperato • Se gli utenti hanno la sensazione d'essere utile per ottenere i risultati saranno invogliati a lasciare feedback positivi • Gli utenti saranno coinvolti durante lo svolgimento del progetto, eliminando il successivo periodo di formazione Migration Strategies 45 Involve The User System Svantaggi: • Gli sviluppatori possono avvertire gli utenti che il loro coinvolgimento può distrarre dal lavoro di reingegnerizzazione del sistema. • Aumento delle aspettative e mettere pressione supplementare sul vostro team. • Può essere difficile coinvolgere gli utenti • Non è possibile coinvolgere tutti, e gli utenti che sono lasciati fuori potrebbero sentirsi trascurati Migration Strategies 46 Involve The User System Conclusioni: • Si utilizzano i feedback per assicurare che si stanno affrontando le reali esigenze del cliente. Migration Strategies 47 Build confidence Obiettivo: • aumentare le chances di avere successo attraverso risultati dimostrativi a ogni fase. Migration Strategies 48 Build confidence Problematiche • Alcuni progetti vogliono dei requisiti e devono rientrare in un badget. • Gli utenti raramente dicono ciò che realmente vogliono • Difficoltà nel convincere gli utenti sui legacy system Migration Strategies 49 Build confidence Soluzione: • creare un atmosfera positiva per dimostrare che molti risultati positivi sono ottenibili grazie a questo clima Fasi: • Suddividere il lavoro in piccoli step per avere il più presto possibile un nuovo risultato Migration Strategies 50 Build confidence Vantaggi • Utenti e sviluppatori possono vedere i reali progressi • Facilità nella stima dei costi Migration Strategies 51 Build confidence Svantaggi • sincronizzazione • avere successo aumenta le aspettative • lavoro extra • Alcuni requisiti sono difficili da dividere. • Re-ingegnerizzazione difficile • Difficoltà nel convincere gli utenti e gli sviluppatori Migration Strategies 52 Build confidence Conclusioni • lavorando a piccoli step si riducono i rischi, aumentano la confidenza e si tiene sempre traccia sul progresso del lavoro Migration Strategies 53 Migrate Systems Incrementally • Obiettivo: Evitare la complessità e il rischio di big-bang reengineering causati dai frequenti implementazioni. Migration Strategies 54 Migrate Systems Incrementally Problematiche • I progetti spesso sono sviluppati guardando avanti, ma questo può portare a nuove richieste • Le reali richieste vengono fuori sempre dopo. • Più tardi si distribuisce il sistema e più tardi arrivano i feedback • Impossibile distribuire un sistema incompleto Migration Strategies 55 Migrate Systems Incrementally Soluzione Implementare un primo aggiornamento del sistema legacy non appena è possibile e migrazione incrementale. Passi • Decomposizione del sistema legacy. • Scegliere una parte da analizzare. • Mettere in atto i test per la parte e le parti che dipendono da essa. • Prendere le misure opportune per il wrap, la reengineer o la sostituituzione la componente. • Distribuire i componenti aggiornati e ottenere un feedback. Migration Strategies 56 Migrate Systems Incrementally Vantaggi • È possibile ottenere subito il feedback degli utenti. • Si vede quello che il sistema fa alla fine di ogni fase. • Gli utenti imparano questo nuovo sistema durante la sua costruzione. • Il sistema è sempre implementato. • Il sistema è in fase di sperimentazione, non è possibile saltare i test. Migration Strategies 57 Migrate Systems Incrementally Svantaggi • Si dovranno impiegare risorse per mantenere il sistema in esecuzione • Difficoltà nella migrazione verso una nuova architettura • Rischioso cambiare un sistema che si sta ancora utilizzando Migration Strategies 58 Migrate Systems Incrementally Conclusioni • Ottenere i feedback positivi • Utenti invogliati se utilizzano molto frequentemente il sistema e non hanno problemi Migration Strategies 59 Prototype the Target Solution • Obiettivo: valutare il rischio di migrazione verso una nuova soluzione mediante la costruzione di un prototipo. Migration Strategies 60 Prototype the Target Solution • Problematiche: – E’ rischioso effettuare cambiamenti radicali su un sistema funzionante. – Difficoltà nell’analizzare l’impatto dei cambiamenti del sistema con le funzionalità esistenti. • Soluzione: – Sviluppare un prototipo della nuova soluzione e valutare con riguardo i nuovi requisiti. Migration Strategies 61 Prototype the Target Solution • Suggerimenti: – Identificazione dei più grossi rischi tecnici del progetto di reengineering: • Scelta di una nuova architettura. • Migrazione dei dati del legacy al nuovo sistema. • Decidere se implementare un prototipo esplorativo o piuttosto un prototipo evolutivo. Migration Strategies 62 Prototype the Target Solution – Un prototipo esplorativo sarà utile per valutare la fattibilità di una scelta tecnica. Deve essere progettato per rispondere a domande che possono riguardare: • Questioni tecniche, (esempio: se la nuova piattaforma è in grado di soddisfare i limiti di prestazioni fissati dal sistema legacy), • Questioni di usabilità che richiedono la partecipazione e la valutazione da parte degli utenti. Migration Strategies 63 Prototype the Target Solution - Un prototipo evolutivo, è destinato a, eventualmente, sostituire un componente del sistema legacy. La nuova architettura non può più solo sostenere adeguatamente i servizi del sistema legacy, ma anche superare le gli ostacoli che limitano le soluzioni del sistema. Il prototipo deve essere progettato anche per superare tali limiti. Migration Strategies 64 Prototype the Target Solution • Vantaggi: – Un prototipo può essere costruito velocemente in quanto non deve implementare tutte le funzionalità del sistema. – E’ possibile “tagliare” parti del sistema legacy per rendere avviabile il prototipo. – Aiuta a capire se la nuova soluzione può funzionare. • Svantaggi: – Gli sviluppatori non sono motivati a spendere tempo per sviluppare i prototipi. Migration Strategies 65 Always Have a Running Version • Obiettivo: Aumentare la fiducia nei cambiamenti grazie a un regolare rebuild del sistema. Migration Strategies 66 Always Have a Running Version • Problematiche: – Può essere difficile fare la demo di un sistema software in fase di sviluppo, o di discutere i problemi con gli utenti, poiché spesso la demo non è stabile. – L’Integrazione delle modifiche di più versioni del sistema può risultare molto complessa e lenta. • Soluzione: – Instituire un processo di integrazione dei nuovi cambiamenti e sviluppi quotidianamente. Migration Strategies 67 Always Have a Running Version • Suggerimenti: – Avere a disposizione sia un sw di gestione delle versioni che di gestione delle configurazioni. (SVN) – Assicurarsi di avere i regression test delle parti su cui si sta lavorando. – Creare un processo per controllare le componenti del sistema e che esegua i regression Test. Le iterazioni del processo devono essere più brevi possibili in modo da consentire cambiamenti che dovranno essere integrati nel sistema funzionante. Migration Strategies 68 Always Have a Running Version • Vantaggi: – Si ha sempre una versione funzionante che può essere usata come demo. – Si ha sempre una versione funzionante su cui avviare i regression test. – Si possono validare velocemente le modifiche al sistema. • Svantaggi: – Bisogna integrare sempre e continuamente le modifiche. Migration Strategies 69 Regression Test After Every Change • Obiettivo: Aumentare la confidenza essendo sicuri che quello che funzionava prima funzioni ancora. Migration Strategies 70 Regression Test After Every Change • Problematiche: – In un sistema complesso, anche piccoli cambiamenti possono avere effetti collaterali, imprevisti. Un cambiamento apparentemente innocuo può creare enormi bug, senza che essi vengano immediatamente scoperti. • Soluzione: – Eseguire il test suite ogni volta si pensi di aver raggiunto uno stato stabile del sistema Migration Strategies 71 Regression Test After Every Change • Vantaggi: – E’ più facile che costruirsi ogni volta una versione funzionante. • Svantaggi: – E’ necessario scrivere i test. – I sistemi legacy non dispongono di adeguati regression test. Ci si dovrà aiutare con Grow Your Test Base Incrementally Migration Strategies 72 Regression Test After Every Change • Conclusioni: – Regression Test After Every Change garantisce che quello che funzionava prima funziona ancora. – Se si costruiscono costantemente i test, oltre che scoprire i vari difetti del software, si otterrà una suite test riusabile che aumenterà la fiducia nelle modifiche fatte. Migration Strategies 73 Make a Bridge to the New Town OBIETTIVO: Migrare i dati dal legacy system al nuovo sistema, in parallelo mentre sono entrambi in esecuzione con un bridge tra i due. PROBLEMA: Come migrare in modo incrementale i dati dal legacy system al nuovo sistema mentre entrambi sono in funzione ? Problema difficile perché: • Alcune componenti del legacy system potrebbero essere in fase di sostituzione; • La sostituzione di componenti critiche è molto rischiosa; • Durante la migrazione, i dati utilizzati da un legacy devono essere Migration Strategies disponibili; 74 Make a Bridge to the New Town Soluzione: costruire un data bridge per trasferire incrementalmente i dati dal legacy system al nuovo sistema, in modo automatico quando le nuove componenti richiedono i dati dalle rispettive componenti del legacy. Come costruire la soluzione: • Identificare le componenti del legacy system e del nuovo sistema che gestiscono gli stessi dati; • Implementare un data bridge: – Invisibile al nuovo sistema; – Responsabile per qualunque conversione di dati; – Ridireziona le richieste di lettura dal nuovo componente al legacy, se i dati non sono già migrati. • Modificare la componente del legacy per ridirezionare le richieste di scrittura alla nuova componente in modo che i nuovi dati siano aggiornati; • Quando tutti i dati sono stati trasferiti rimuovere il bridge e il componente75 Migration Strategies legacy. Make a Bridge to the New Town New System Component 3: external write 1: read 1.1: read Legacy System Component 3.1: external write Data Bridge 1.2: write 3.2: external write Data Store Richiesta di scrittura dall’esterno (utente o altro sistema). Richiesta di lettura dal nuovo componente. Migration Strategies 76 Make a Bridge to the New Town Vantaggi: • Iniziare ad utilizzare il nuovo sistema senza aver terminato la fase di migrazione dei legacy data. Svantaggi: • Senza l’esistenza di un mapping chiaro tra i legacy data e i dati del nuovo sistema, è difficile implementare un bridge • Una volta che il trasferimento è avvenuto è difficile tornare indietro • Aumento del overhead generale causato dal bridge Conclusione Un bridge tra il vecchio e il nuovo sistema permette agli utenti di iniziare ad utilizzare il nuovo sistema prima che sia completo; il bridge isola i due sistemi architettura del nuovo sistema non è influenzata dal legacy system. Relazioni con altri pattern: Migration Strategies • Migrate your system incrementally 77 Present the Right Interface PROBLEMA Durante il processo di migrazione, il nuovo sistema come accederà ai servizi del legacy system ? Problema difficile perché: • Il nuovo sistema non è ancora completo deve utilizzare i servizi del legacy; • Il legacy non ha le giuste interfacce necessarie al nuovo sistema. Problema risolvibile • Non bisogna accedere ai servizi del legacy direttamente. Migration Strategies 78 Present the Right Interface Soluzione • Identificare le astrazioni (interfacce) per il nuovo sistema e usare dei wrapper per il vecchio sistema in modo da emulare le nuove astrazioni. • Esempio: libreria grafica in linguaggio procedurale da utilizzare in un sistema object-oriented. – Troppo costoso reimplementarla nell’ottica object-oriented. – Soluzione 1: libreria come una classe utility (static) – Soluzione 2: creare un modulo wrapper che presenta la giusta interfaccia object-oriented. Vantaggi • Separare il nuovo sistema dai servizi del legacy system fin dall’inizio usando le giuste astrazioni; • Ridurre il rischio che la nuova architettura venga influenzata dalla vecchia. Migration Strategies 79 Present the Right Interface Svantaggi: • Le nuove interfacce potrebbero non essere stabili. • Sbagliare nel creare le giuste astrazioni (wrappare codice procedurale come utility class) Conclusione • Introduce un nuova e più adatta interfaccia per le componenti del legacy system. • Scegliere la giusta interfaccia non costringe a pensare in termini di design del legacy system e permette di considerare approcci alternativi. Relazioni con altri pattern • Deprecate Obsolete Interfaces • Distinguish Public from Published Interface Migration Strategies 80 Distinguish Public from Published Interface OBIETTIVO • Facilitare lo sviluppo parallelo, distinguendo interfacce published instabili da interfacce public stabili. PROBLEMA • Come permettere la migrazione da interfacce del legacy a interfacce del nuovo sistema mentre queste ultime sono ancora in fase di sviluppo ? Problema difficile perché • Migrazione al nuovo sistema il più presto possibile; • Non congelare le interfacce delle componenti del nuovo sistema troppo presto; • Cambiare le interfacce a un componente che è largamente usato può rallentare lo sviluppo; Problema risolvibile Migration Strategies • Lo stato delle interfacce può essere controllato. 81 Distinguish Public from Published Interface Soluzione • Fare una distinzione tra le interfacce – Public: identificano componenti pronte per essere utilizzate dal resto del sistema; – Published: identificano componenti che sono ancora instabili per essere utilizzati in modo definitivo dall’intero sistema, ma posso essere utilizzabili da un sottosistema. Come costruire la soluzione • Le interfacce “published” non sono supportate dai linguaggi di programmazione utilizzare strategie alternative (convenzione sui nomi): – JAVA: dichiararle come protected public quando diventano stabili; – C++: dichiarale public o protected e inoltre dichiarare friends le componenti che possono utilizzarle public quando diventano stabili e rimuovere la dichiarazione friends. Migration Strategies 82 Distinguish Public from Published Interface Vantaggi: • I client che utilizzano interfacce published sono consapevoli che saranno modificate. Svantaggi: • Trasformare un’interfaccia da published a public comporta un overhead per i client che dovrebbero aggiornarsi alla nuova interfaccia; • Dubbio: un client dovrebbe usare interfacce non stabili o i servizi del legacy system ? Conclusioni • Quando si crea una nuova interfaccia (Present the right interface), questa potrebbe non essere stabile, allora bisogna distinguere tra interfacce published e public. Quando le interfacce diventano stabili vengono definite public e quelle obsolete eliminate. Migration Strategies 83 Deprecate Obsolete Interfaces OBIETTIVO: Lasciare agli utenti il tempo di reagire ai cambiamenti delle public interface “etichettando” quelle obsolete come “deprecate”. PROBLEMA – Come modificare un’interfaccia evitando di “spiazzare” tutti gli utenti? Problema Difficoltoso : - potrebbe provocare perdita di utenti (DA UN LATO); - lasciare un’interfaccia obsoleta causa problemi di manutenzione futura (DALL’ALTRO LATO); - non tutti i cambiamenti sono proficui. Migration Strategies 84 Deprecate Obsolete Interfaces LA SOLUZIONE E’ FATTIBILE: - L’interfaccia vecchia e quella che la deve sostituire possono coesistere per un periodo di tempo. QUINDI… Etichettare la vecchia ed obsoleta interfaccia come “deprecata” così da segnalare all’utente che verrà certamente rimossa e sostituita da una migliore nella prossima release. Migration Strategies 85 Deprecate Obsolete Interfaces SOLUZIONE: - Implementare la nuova interfaccia e “deprecare” quella vecchia; - Deprecare = informare i clienti che l’interfaccia subirà modifiche atte al miglioramento; - Valutare per quanto la vecchia interfaccia debba essere usata e se si possa già eliminare in una prossima release. NOTA: In Java, il meccanismo di “deprecazione” è una funzionalità: aggiungendo “@deprecate” nel javadoc si effettua l’operazione citata, inoltre anche il compilatore genera warning se il codice è compilato con l’opzione “-deprecate”. Migration Strategies 86 Deprecate Obsolete Interfaces ALTRO APPROCCIO: - Informare gli utenti della deprecazione di interfacce inserendo ciò nella documentazione; - Spostare o rinominare il componente deprecato. I clienti possono continuare ad utilizzare tale componente ma devono adattarsi a compilarlo ogni volta; - Rimpiazzare i componenti deprecati con componenti identici ma che in più generano warning. Migration Strategies 87 Deprecate Obsolete Interfaces PRO: Gli utenti non devono abituarsi istantaneamente ai cambiamenti; C’è il tempo di adattare la mente ai cambiamenti. CONS: Gli utenti sono liberi di ignorare la deprecazione. DIFFICOLTA’: E’ difficile rintracciare tutti gli utenti che utilizzano un determinato componente deprecato; E’ difficile capire quando deprecare un componente. BENEFICI: La deprecazione impone ai progettisti di effettuare una valutazione sull’impatto dei cambiamenti Migration che si Strategies vogliono introdurre. 88 Conserve Familiarity OBIETTIVO: Evitare cambiamenti radicali che potrebbero alienare l’utente. PROBLEMA – Come effettuare una revisione accurata di un sistema legacy senza interrompere il modo di operare degli utenti che lo utilizzano per compiere il loro lavoro? Problema Difficoltoso : - I sistemi legacy prevedono cambiamenti “importanti”; - Gli utenti non sono soddisfatti dei sistemi legacy ma li capiscono bene. Migration Strategies 89 Conserve Familiarity LA SOLUZIONE E’ FATTIBILE: - E’ possibile effettuare una migrazione incrementale verso una nuova e migliore soluzione. QUINDI… Introdurre solo una costante, cioè un basso numero di cambiamenti tra una release e la successiva. Migration Strategies 90 Conserve Familiarity PRO: Ogni release non impone dei cambiamenti significativi e drastici dei modi di lavoro degli utenti (è tutto graduale). DIFFICOLTA’: Qualche volta sono necessari dei drastici e radicali cambiamenti. CONCETTO CHIAVE: Troppi cambiamenti tra le release incrementano il rischio di difetti e decrementano la capacità di adattarsi degli utenti. Migration Strategies 91 Use Profiler Before Optimizing OBIETTIVO: Evitare sforzi di reengineering relativi all’ottimizzazione ed alla verifica della presenza di colli di bottiglia. PROBLEMA – Quando di deve effettivamente riscrivere una porzione di codice che è evidentemente inefficiente? Problema Difficoltoso : - nella reingegnerizzazione del software si possono trovare molti algoritmi semplici ed “ingenui” nel codice legacy; - può essere difficile prevederne l’impatto sulle performance e si può perdere tanto tempo nel fare supposizioni; - il codice ottimizzato è sempre più complicato. Migration Strategies 92 Use Profiler Before Optimizing LA SOLUZIONE E’ FATTIBILE: - Esistono tool che individuano dove potrebbero esserci dei problemi di performance. SOLUZIONE: Prima di ottimizzare una parte di sistema che è chiaramente inefficiente si deve utilizzare un “profiler” che esprime se essa è un potenziale collo di bottiglia. Non ottimizzare nulla fino ad un riscontro (positivo) da parte del profiler. Qualora si decidesse di proseguire, creare dei banchmark che dimostrano i guadagni di prestazione. Migration Strategies 93 Use Profiler Before Optimizing PRO: Nessuno spreco di tempo nell’ottimizzazione delle parti che non producono significativi miglioramenti di performance. CONS: Gli algoritmi “ingenui” sopravvivono comunque a lungo nel sistema. NOTAZIONI: Il miglioramento delle performance di una porzione di codice dipende da quanto tempo il programma rimane in run su quella porzione (questa informazione è data dal profiler). Migration Strategies 94