Lezione 3: Sviluppo in Extreme Programming

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    1 Favorite

    Lezione 3: Sviluppo in Extreme Programming - Presentation Transcript

    1. Lezione 19: Sviluppo in Extreme Programming Corso di Ingegneria del Software Laurea Magistrale in Ing. Informatica Università degli Studi di Salerno 1
    2. Outline ✦ Progettazione in XP ✦ Principi di progettazione: Semplicità ✦ Test Driven Development ✦ Self Documenting Code ✦ Once and Only Once ✦ You Ain’t Gonna Need It ✦ Automazione dei test in Java: JUnit 2
    3. Progettazione in XP ✦ Anche la progettazione viene effettuata in maniera incrementale ✦ Non c’è una singola figura responsabile della progettazione • tutto il team condivide la responsabilità di progettazione ✦ Non viene prodotta una documentazione formale della progettazione, specialmente per la progettazione di dettaglio 3
    4. CRC Cards ✦ Lo strumento principale usato durante la discussione delle scelte progettuali sono le schede Class-Responsibility- Collaboration (CRC Cards) ✦ Ogni scheda (tipicamente scritta a mano durante la discussione) indica: • il nome di una classe • le responsabilità della classe • le altre classi con cui essa interagisce 4
    5. CRC Cards 5
    6. CRC Cards ✦ Le schede CRC non fanno parte della documentazione mantenuta e tracciata nel progetto ✦ Sono utilizzate esclusivamente come ausilio durante la discussione, e come promemoria delle decisioni prese 6
    7. The Source Code is the Design ✦ In XP la descrizione ufficiale delle scelte progettuali non è in un documento formale, ma è il codice sorgente stesso (inclusi i commenti)! • lavorando su piccoli incrementi, non è necessario avere una documentazione formale dettagliata per guidare lo sviluppo • se necessario è possibile “estrarre” con strumenti automatici una rappresentazione più astratta del design dal codice sorgente (es. diagrammi UML); in ogni caso è il codice il riferimento autoritativo 7
    8. The System Metaphor ✦ Anche se non si documentano le decisioni progettuali di basso livello, in genere è necessaria una descrizione dell’architettua ✦ A questo scopo si usa la System Metaphor: • documento informale e conciso • descrive in termini di alto livello la struttura del sistema e i concetti fondamentali, spesso attraverso analogie • ha lo scopo di facilitare la comunicazione tra gli sviluppatori e di stabilire un linguaggio comune 8
    9. Progettazione in XP ✦ La linea guida fondamentale: Do the simplest thing that possibly work “Tutto ciò che è complesso non è utile. Tutto ciò che è utile è semplice.” M. Kalashnikov 9
    10. The simplest thing... ✦ La “cosa più semplice” può avere diversi significati: • la prima cosa che viene in mente • la cosa che si realizza con il minore sforzo • la cosa che può capire anche chi non ha molta conoscenza/competenza • ... ✦ Nessuno di questi significati corrisponde al concetto di semplicità richiesto da XP 10
    11. The simplest thing... ✦ Il codice più semplice per risolvere un problema è quello che: • supera tutti i test • esprime ogni idea che gli sviluppatori intendevano esprimere • contiene ogni concetto una sola volta • non ha parti superflue 11
    12. Test Driven Development ✦ Il codice che risolve un problema deve superare tutti i test ✦ Le metodologie tradizionali posizionano il testing alla fine del ciclo di sviluppo, quando il codice è completo ✦ XP adotta un approccio diametralmente opposto: Test Driven Development (TDD) 12
    13. Test Driven Development ✦ Il TDD si può riassumere nelle seguenti raccomandazioni: • Test Early • Test Often • Test Automatically 13
    14. Test Early ✦ Nell’aggiungere una nuova funzione al programma, lo sviluppatore: • innanzitutto scrive l’interfaccia con un’implementazione vuota • quindi scrive il codice per testare la nuova funzione (unit tests) • implementa la funzione • verifica che l’implementazione supera il test • verifica che tutte le altre funzioni precedentemente implementate superino i loro test • solo a questo punto il lavoro sulla funzione è 14 completo
    15. Test Early ✦ Benefici: • lo sviluppatore verifica l’usabilità dell’interfaccia della funzione • lo sviluppatore verifica la sua comprensione dei requisiti • il testing non è relegato alla fine del progetto, quando la prossimità della deadline può spingere a farlo in maniera frettolosa e approssimativa • la necessità di testare una singola funzione per volta spinge lo sviluppatore a progettare codice con basso accoppiamento 15
    16. Test Often ✦ Il codice dei test non è eseguito una volta sola: • ad ogni modifica del software vengono eseguiti i test non solo della parte modificata ma anche di tutte le altre parti del software • il codice sviluppato viene integrato nella versione corrente del software solo se supera tutti i test 16
    17. Test Often ✦ Benefici: • i bug vengono individuati presto nel ciclo di sviluppo, quando è più semplice circoscriverne la causa • gli sviluppatori possono modificare con più tranquillità il codice esistente, sapendo che se dovessero introdurre dei bug essi sarebbero subito rilevati • il numero di bug che finiscono nella versione rilasciata del software è significativamente minore • si evita la “regressione” del software (si parla anche di “test di regressione”) 17
    18. Test Automatically ✦ I test devono essere eseguibili automaticamente (senza intervento dell’utente) ✦ Un solo comando deve consentire di lanciare tutti i test del progetto ✦ Lo sviluppatore deve avere i risultati dei test in forma sintetica (es. quanti sono i test falliti) con la possibilità, se ne ha bisogno, di ottenerli in forma analitica (quali sono i test falliti) 18
    19. Test Automatically ✦ Benefici: • gli sviluppatori sono incoraggiati a eseguire i test spesso, dal momento che devono lanciare un singolo comando • è possibile usare programmi che lanciano i test periodicamente (es. ogni notte) e avvisano i responsabili del progetto dei risultati • poiché non è possibile automatizzare il testing dell’interfaccia utente (se non in maniera limitata), gli sviluppatori sono incoraggiati a separare l’interfaccia utente dalla business logic 19
    20. TDD e Refactoring ✦ Cambiamenti di implementazione ma non di interfaccia: • i test già esistenti consentono di verificare che la nuova implementazione è compatibile con la vecchia ✦ Cambiamenti di interfaccia a livello sintattico: • occorre modificare tutti i test della funzione ✦ Cambiamenti di interfaccia a livello semantico: • occorre esaminare tutti i test della funzione per verificare che siano coerenti con la nuova 20 semantica
    21. TDD e debugging ✦ Quando si scopre un bug non rilevato dai test: • innanzitutto si crea un nuovo test che fallisca a causa del bug • solo a questo punto si provvede a eliminare il bug ✦ Benefici: • un bug eliminato una volta non rischia di essere reintrodotto in una successiva modifica del codice 21
    22. Self Documenting Code ✦ Il codice più semplice deve esprimere ogni idea che gli sviluppatori intendevano esprimere • non mettere l’implementazione di idee non correlate nella stessa funzione/classe/metodo (Alta coesione) • l’organizzazione delle unità del programma dovrebbe rendere comprensibile l’organizzazione delle idee • i nomi delle entità del programma dovrebbero rendere chiaro il loro significato minimizzando la documentazione necessaria 22
    23. Self Documenting Code ✦ Principio della Minima Sorpresa: tra le possibili interpretazioni di un frammento di programma, quella corretta dovrebbe essere quella più ovvia per lo sviluppatore • convenzioni di codifica comuni • convenzioni comuni per la scelta dei nomi ‣ la difficoltà nella scelta del nome di una classe, funzione o altra entità, spesso è indice di una cattiva progettazione: l’entità in questione non ha una singola responsabilità ben definita 23
    24. Self Documenting Code ✦ Benefici • riduzione della necessità di documentazione esplicita ‣ uso di strumenti di documentazione automatica come JavaDoc ‣ eventuali altri tipi di documentazione sono prodotti solo su richiesta dell’utente • maggiore semplicità di manutenzione, anche per sviluppatori diversi dal team iniziale 24
    25. Once and Only Once ✦ Ogni informazione deve avere una rappresentazione unica, non ambigua e autoritativa all’interno del sistema • in letteratura si parla anche di “principio DRY” (Don’t Repeat Yourself) • vale sia per i dati che per il codice del sistema • non esclude la presenza di copie “meccaniche” delle informazioni (es. cache), ma deve essere unica la rappresentazione a cui gli sviluppatori fanno riferimento 25
    26. Once and Only Once ✦ Benefici: • è minore il rischio di introdurre incongruenze • è più facile modificare il sistema 26
    27. Once and Only Once ✦ In generale non è banale applicare nel modo migliore questo principio: • non sempre è facile riconoscere che due parti del programma fanno qualcosa di simile • spesso la duplicazione si manifesta solo astraendo l’informazione rispetto a un insieme di parametri ✦ Tuttavia ci sono alcune violazioni grossolane facili da individuare: • Cut and Paste programming • costanti letterali nel codice • ... 27
    28. Once and Only Once ✦ Questo principio rappresenta la principale forza che guida il Refactoring di un programma: • periodicamente, dopo l’aggiunta di una o più funzioni, gli sviluppatori esaminano il programma per individuare nuove opportunità di rimuovere duplicazioni • in questo modo si evita che la struttura del programma possa “andare alla deriva” durante il ciclo di sviluppo 28
    29. Parti superflue ✦ Il programma non deve contenere parti superflue • occorre rimuovere le parti che non sono più necessarie • occorre evitare di introdurre nuove funzioni che non sono ancora necessarie 29
    30. Parti superflue ✦ Benefici: • le parti superflue rendono più complicata la struttura del programma, e aumentano le sue dimensioni • le parti superflue possono contribuire all’introduzione di bug (es. ARIANE 5) 30
    31. Necessità future ✦ Spesso gli sviluppatori hanno la tentazione di aggiungere nuove funzioni che non sono attualmente necessarie • previsione che queste funzioni possano essere utili in futuro • previsione che il costo per implementare queste funzioni sia trascurabile • queste funzioni sono “interessanti da realizzare” ✦ Questa tendenza può manifestarsi anche rendendo più generale del necessario una funzione 31
    32. You Ain’t Gonna Need It ✦ In XP si raccomanda di contrastare questa tendenza: • gli sviluppatori devono lavorare sui requisiti noti oggi, non su ipotesi infondate su quelli futuri • le esigenze future potrebbero essere diverse da quelle previste • cercare di anticipare le esigenze future introduce parti superflue nel programma ✦ Convenzionalmente si usa la frase “You Ain’t Gonna Need It” (abbreviata in YAGNI) per indicare questa raccomandazione 32
    33. Automazione dei test in Java ✦ Abbiamo visto che il Test Driven Development richiede l’automatizzazione degli Unit Test ✦ Il modo con cui è possibile automatizzare i test dipende dal linguaggio e dall’ambiente di sviluppo ✦ Per il linguaggio Java lo standard de facto è la libreria JUnit 33
    34. JUnit ✦ Creata da K. Beck e E. Gamma come porting al linguaggio Java del framework SUnit, sviluppato da Beck per il linguaggio Smalltalk ✦ “Pure Java”, portabile su qualsiasi piattaforma ✦ Utilizzabile attraverso la command line, ma anche supportata direttamente da ambienti di sviluppo come Eclipse 34
    35. JUnit ✦ Sito: http://junit.org ✦ Nota: • faremo riferimento alla versione 4.xx di JUnit, che richiede il JDK 1.5 o successivi • per lavorare con JDK precedenti a 1.5 occorre la versione 3.xx di JUnit, meno semplice da usare 35
    36. Installazione di JUnit ✦ Dobbiamo ottenere il file junit-4.xx.jar dal sito (ad es. la versione corrente è junit-4.5.jar) • NOTA: la versione corrente di Eclipse include tra i plugin di default JUnit 4.3 ✦ Il file .jar deve essere inserito nel classpath di Java sia durante la compilazione che durante l’esecuzione dei test 36
    37. Uso di JUnit ✦ Tipicamente, per ogni classe da testare si crea una classe di test; per convenzione il nome della classe di test si ottiene aggiungendo “Test” al nome della classe da testare • Esempio: se abbiamo una classe Adder, gli unit test di questa classe saranno nella classe AdderTest 37
    38. Uso di JUnit ✦ Note: • la classe di test deve essere dichiarata public • se la classe da testare ha metodi protected o visibili a livello di package, la classe di test deve trovarsi nello stesso package ✦ Nel file .java della classe di test occorre inserire le seguenti direttive: import org.junit.*; import static org.junit.Assert.*; 38
    39. Uso di JUnit: metodi di test ✦ Nella classe di test, occorre inserire dei metodi per eseguire i test veri e propri ✦ Per convenzione, il nome di questi metodi è testNomeMetodo, dove nomeMetodo è il nome del metodo da testare ✦ I metodi di test devono essere dichiarati come: @Test public void testAdd() { // implementazione del test // per il metodo ‘add’ ....... } 39
    40. Uso di JUnit: metodi di test ✦ Nota: @Test è una annotazione che segnala a JUnit che il metodo seguente è un metodo di test; la classe di test potrebbe contenere altri metodi ausiliari che non devono essere eseguiti direttamente da JUnit 40
    41. Uso di JUnit: asserzioni ✦ All’interno dei metodi di test si richiamano dei metodi il cui nome è assertCondizione per specificare le condizioni che devono essere verificate ✦ Al momento dell’esecuzione, un test si considera superato se tutte le condizioni specificate risultano verificate 41
    42. Uso di JUnit: asserzioni ✦ Principali asserzioni di JUnit: • 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 42
    43. Uso di JUnit: asserzioni ✦ È possibile aggiungere anche una stringa come primo parametro per identificare la particolare condizione nell’output del test: • assertEquals(message, expected, actual) • assertTrue(message, cond) • assertFalse(message, cond) • ... 43
    44. Uso di JUnit: esempio ✦ Supponiamo di voler realizzare una classe che effettui le addizioni tra numeri interi ✦ Seguendo i principi del TDD, cominciamo a definire l’interfaccia della classe: public class Adder { public int add(int a, int b) { // implementazione vuota! return 0; } } 44
    45. Uso di JUnit: esempio ✦ Definiamo ora una classe di test per Adder nel file “AdderTest.java”: import org.junit.*; import static org.junit.Assert.*; public class AdderTest { // qui vanno i metodi di test } 45
    46. Uso di JUnit: esempio ✦ Aggiungiamo un metodo per testare il metodo add di Adder: import org.junit.*; import static org.junit.Assert.*; public class AdderTest { @Test public void testAdd() { // qui va il codice del test } } 46
    47. Uso di JUnit: esempio ✦ Infine scriviamo il codice del test, usando le asserzioni per specificare le condizioni che devono essere verificate: import org.junit.*; import static org.junit.Assert.*; public class AdderTest { @Test public void testAdd() { Adder a=new Adder(); assertEquals(7, a.add(4,3)); assertEquals(5, a.add(10,-5)); } } ✦ A questo punto la classe di test è completa e può essere compilata 47
    48. Uso di JUnit: esecuzione ✦ Ci sono diversi modi di mandare in esecuzione i test: • dalla linea di comando • creando un main in Java • direttamente dall’ambiente di sviluppo Eclipse • ... 48
    49. Uso di JUnit: esecuzione ✦ Dalla linea di comando: • java org.junit.runner.JUnitCore className... • esempio: foggia% java org.junit.runner.JUnitCore AdderTest JUnit version 4.5 .E Time: 0,008 There was 1 failure: 1) testAdd(AdderTest) java.lang.AssertionError: expected:<7> but was:<0> at org.junit.Assert.fail(Assert.java:91) at org.junit.Assert.failNotEquals(Assert.java:618) at org.junit.Assert.assertEquals(Assert.java:126) at org.junit.Assert.assertEquals(Assert.java:145) at AdderTest.testAdd(AdderTest.java:8) . . . . . FAILURES!!! Tests run: 1, Failures: 1 49
    50. Uso di JUnit: esecuzione ✦ Dall’ambiente di sviluppo Eclipse: • dopo aver selezionato una classe di test, un package o l’intero progetto, si usa il comando: ‣ Run > Run As... > JUnit Test 50
    51. Uso di JUnit: esecuzione ✦ Nota: nel riportare i risultati dei test, JUnit usa due termini diversi per indicare i problemi incontrati: • failure: il test è stato eseguito, e (almeno) una delle condizioni specificate è risultata falsa • error: si è verificato un errore che ha impedito l’esecuzione del test 51
    52. Uso di JUnit: time-out ✦ È possibile specificare che un metodo di test debba considerarsi fallito se non completa il suo lavoro entro un tempo prestabilito • il time-out va specificato in millisecondi, come parametro dell’annotazione @Test @Test(timeout=3000) // 3 secondi public void testAdd() { // implementazione del test // per il metodo ‘add’ ....... } 52
    53. Uso di JUnit: eccezioni ✦ È possibile specificare che un metodo di test debba sollevare una specifica eccezione, oppure si considera fallito: • l’eccezione va specificata passando l’oggetto Class che la rappresenta come parametro di @Test @Test(expected=NotFound.class) public void testSearch() { // implementazione del test // per il metodo ‘search’ ....... } 53
    54. Uso di JUnit: Fixture ✦ Spesso occorre realizzare più test che utilizzano un insieme di oggetti comuni ✦ Dover creare questi oggetti all’interno di ciascun metodo di test porta a una duplicazione del codice ✦ Per ovviare a questo inconveniente, in JUnit si crea una “fixture”: un insieme di oggetti (associati a variabili di istanza della classe di test), che vengono reinizializzati prima di lanciare ogni test 54
    55. Uso di JUnit: Fixture ✦ L’annotazione @Before consente di specificare un metodo che deve essere lanciato prima di eseguire ciascuno dei metodi di test ✦ In questo modo è possibile specificare come inizializzare la fixture prima dell’esecuzione di ciascun test ✦ È disponibile anche l’annotazione @After per specificare operazioni da eseguire dopo ciascun test 55
    56. Uso di JUnit: Fixture import org.junit.*; ✦ Esempio: import static org.junit.Assert.*; public class AdderTest { private Adder a; @Before public void setUp() { a=new Adder(); } @Test public void testAddPositive() { assertEquals(7, a.add(4,3)); } @Test public void testAddNegative() { assertEquals(5, a.add(10,-5)); } } 56

    + AndrewRiotAndrewRiot, 4 months ago

    custom

    201 views, 1 favs, 0 embeds more stats

    ✦ Progettazione in XP
    ✦ Principi di progettazio more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 201
      • 201 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 1
    • Downloads 0
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories