Miglioramento della Q ualità del Software con attività di ... · aiuta altresì a creare software...

48
Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in Ingegneria del Software Miglioramento della Qualità del Software con attività di Refactoring Anno Accademico 2015/2016 Candidato: Vincenzo Coscia matr. N46002063

Transcript of Miglioramento della Q ualità del Software con attività di ... · aiuta altresì a creare software...

Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in Ingegneria del Software

Miglioramento della Qualità del Software con attività di Refactoring

Anno Accademico 2015/2016 Candidato: Vincenzo Coscia matr. N46002063

Indice

Introduzione 3

1 Qualità del Software 51.1 Qualità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.1.1 Standard di Qualità : ISO/IEC 9126 . . . . . . . . . . . . 51.1.2 Metriche di Qualità . . . . . . . . . . . . . . . . . . . . . 7

2 Refactoring 112.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.2 Refactoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.3 Bad Smells Code . . . . . . . . . . . . . . . . . . . . . . . . . . 132.4 Refactoring e gli IDE . . . . . . . . . . . . . . . . . . . . . . . . 16

2.4.1 Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . 162.4.2 Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . 17

3 Applicazione Refactoring : Esempio noleggio Film 183.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183.2 Esecuzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193.3 Analisi pre-Refactoring . . . . . . . . . . . . . . . . . . . . . . . 21

3.3.1 CodePro Tool . . . . . . . . . . . . . . . . . . . . . . . . 213.3.2 Applicazione Refactoring . . . . . . . . . . . . . . . . . 23

3.4 Analisi post-Refactoring . . . . . . . . . . . . . . . . . . . . . . 443.5 Esecuzione post-Refactoring . . . . . . . . . . . . . . . . . . . . 46

Conclusione 47

Bibliografia 48

2

Introduzione

La progettazione di un sistema software è frutto di un immenso lavoro, costituitoda diverse fasi che vanno sotto il nome di Ciclo di vita del software. Questo modusoperandi si riferisce al modo in cui una metodologia di sviluppo o un modello diprocesso scompongono l’attività di realizzazione di prodotti software in microattività tra loro coordinate, spesso svolte da diversi team, documentate di volta involta al fine di produrre una documentazione completa che descriva al megliosia ciò per cui il prodotto software è stato progettato sia come il progetto stessoè stato realizzato. Esistono svariati modelli da poter seguire, ma tutti accomunatida una stessa logica operativa:

• Analisi: si svolgono indagini in cui si tengono in conto delle caratteristichechieste dal cliente, dai costi ed aspetti logici della realizzazione.

• Progettazione: si definiscono linee guida sulla realizzazione del software,sulla base dell’Analisi precedentemente svolta.

• Implementazioni & Testing : si codifica il progetto in un linguaggio diprogrammazione, testando il corretto funzionamento.

• Rilascio & Manutenzione : si rilascia all’utente finale il prodotto dopodi-chè si da inizio ad una fase di costante manutenzione atta alla risoluzione dibug che si possono presentare, nonchè al miglioramento delle sue funzioni.

Quest’ultima fase, in particolare per quanto concerne la Manutenzione, è unadelle fasi più importanti in quanto si verifica su larga scala i problemi che nasconoa seguito di un utilizzo massiccio del prodotto realizzato con conseguente realiz-zazione di soluzioni atte alla loro risoluzione, non a caso si stima che il 60% deicosti del software dipende proprio da quest’ultima fase.

Progettare un prodotto di qualità non significa solo avere ottimi riscontri intermini di prestazioni a lungo e breve termine, ma significa soprattutto progettareaffinchè esso sia facilmente modificabile e di facile comprensione, attraverso adesempio l’utilizzo di una nomenclatura semplice e diretta dei vari componenti, il

3

tutto corredato da un buona documentazione stilata, che favorisce la sua manuten-zione. Se consideriamo ad esempio i software definiti Legacy 1, essi molto spessosono irrecuperabili proprio per il fatto di una mancata o errata documentazione,che fa lievitare in maniera significativa il costo della manutenzione, e in generaledi rimessa sul mercato.

L’attività di Refactoring si prefigge come obiettivo proprio quello di suppor-tare, attraverso semplici ma efficaci tecniche, l’attivita di manutenzione al fine dimigliorare il design del codice dopo esser stato scritto. Questa attività si occupa dirisolvere problemi ben precisi, che vanno sotto il nome di Bad Smells, la cui pre-senza crea caos e disordine, nonchè un’elevata probabilità di bug. Questa attivitàaiuta altresì a creare software di Qualità, termine definito nella norma ISO-IEC9126 prodotta dalla IEEE 2 attraverso la definizione di metriche da rispettare.

In questo testo si vuole allora presentare la normativa vigente sulla qualità,prima citata, e definire meglio il concetto di Refactoring. Si passerà poi all’analisidi un semplice codice scritto in linguaggio Java e si verificherà come, attuan-do semplissime tecniche si riesca a migliorare i valori di qualità misurati tramiteun plug-in dell’ambiente di sviluppo utilizzato, nel nostro caso Eclipse, che bensupporta tali attività.

1Con il termine Legacy si intende quella branca di software abbandonati, il cui sviluppo èterminato

2Institute of Electrical and Electronic Engineers

4

Capitolo 1

Qualità del Software

1.1 QualitàCon il termine qualità del software si intende l’insieme delle proprietà e dellecaratteristiche di un prodotto o servizio che conferiscono la capacità di soddisfa-re esigenze espresse o implicite. Può essere intesa allora come una misura, cherileva il grado di soddisfazione rispetto sia al funzionamento e sia alla struttura in-terna del software prodotto. Essa dipende fortemente dalla maturità del processoadoperato per il suo sviluppo.

1.1.1 Standard di Qualità : ISO/IEC 9126Per valutare la qualità di un prodotto software e per dare una definizione più pre-cisa e univoca di qualità si può far riferimento allo standard ISO/IEC 9126, ilquale definisce un modello di qualità standard che definisce univocamente le ca-ratteristiche di qualità di un prodotto software e le metriche attraverso la quale èpossibile misurare tali caratteristiche.

La normativa si divide in 4 parti :

1. Modello di qualità : un insieme di caratteristiche di qualità che descrivonoi fattori di qualità di un prodotto software

2. Metriche esterne : misurano i comportamenti del prodotto software rileva-bili dai test e dall’osservazione durante la sua esecuzione.

3. Metriche interne : utilizzabili durante le fasi di progettazione e di codificaper misurare le proprietà intrinseche del prodotto software. Esse misuranoattributi interni del software e forniscono indicazioni sulle caratteristicheesterne del prodotto finale, tramite l’analisi dei prodotti intermedi.

5

Figura 1.1: Rappresentazione globale del modello ISO-IEC 9126

4. Metriche qualità in uso : misurano il grado con cui il prodotto softwarepermette agli utenti di svolgere le proprie attività in maniera produttiva nelrispetto della sicurezza, portando così soddisfazione nel contesto operativo.

Per determinare quindi la qualità complessiva del prodotto software concorro-no 3 punti di vista:

• Interna : si riferisce alle proprietà rilevanti durante lo sviluppo e la manu-tenzione del software, indipendentemente dall’ambiente di utilizzo e dall’u-tente

• Esterna : esprime le proprietà che caratterizzano il prodotto software du-rante la sua esecuzione.

• Percepita : esprime le proprietà possedute in uno specifico ambiente ocontesto d’uso, nonché l’efficacia ed efficienza con cui il software servele esigente dell’utente. ( Quindi quest’ultima è legata all’utente finale ).

Pare ovvio sottolineare che i tre punti di vista sulla qualità si influenzano a vicen-da: non può esservi qualità percepita positivamente dall’utente se non vi è unabuona qualità intrinseca del codice e delle buone prestazioni. Per il modello diqualità interna ed esterna possiamo suddividerlo in 6 caratteristiche fondamentali:

6

• Funzionalità : capacità del prodotto software di fornire funzioni che sod-disfano le esigenze dell’utente finale

• Affidabilità : la capacità del prodotto software di mantenere buone presta-zioni quando usato sotto specifiche condizioni

• Usabilità : la capacità del prodotto software di essere capito, usato e graditoall’utente finale.

• Efficienza : la capacità del prodotto software di fornire prestazioni appro-priate in relazione alla quantità di risorse necessarie

• Manutenibilità : la capacità del prodotto software di essere modificato ecorretto con facilità.

• Portabilità : la capacità del prodotto software di essere trasferito da unambienta ad un altro

1.1.2 Metriche di QualitàLa Misurazione è il processo attraverso il quale si assegnano valori ad attributi dientità del mondo reale al fine di descriverle secondo regole ben definite: l’Entitàrappresenta l’oggetto sottoposto a misurazione, un suo Attributo è l’aspetto di ta-le oggetto che interessa descrivere. Nell’Ingegneria del Software le entità oggettodi misurazione sono sostanzialmente due:

• Processo, che misurano le caratteristiche principale del processo di svilup-po e di manutenzione del software. Si trovano in questo ambito caratteristi-che come Costi e Tempi di sviluppo .

• Prodotto, che misurano la qualità del prodotto in merito alle sue caratteri-stiche fisiche. Si trovano in questo ambito caratteristiche come Dimensioni,Funzionabilità e Manutenibilità.

Metrica1: misura quantitativa del grado di possesso di uno specificoattributo da parte di un sistema, un componente, o un processo.

La normativa ISO/IEC 9126 prevede 3 insiemi di metriche:

• Metrica Interna2 : misura aspetti del software non eseguibile

1IEEE Standard 610.12-1990: IEEE Standard Glossary of Software Engineering Terminology2ISO-IEC 9126-2

7

Figura 1.2: Ciclo di qualità del software

• Metrica Esterna3 : misura aspetti del software osservabili in fase di esecu-zione

• Metrica di Qualità in Uso4 : misura fino a che punto un prodotto softwaresoddisfa i bisogni dell’utente per raggiungere specifici scopi con efficacia,produttività e sicurezza in un determinato contesto d’uso.

In generale, le metriche per valutare la qualità di un prodotto software devono es-sere semplici e calcolabili, coerenti e obiettive e soprattutto indipendenti dal lin-guaggio di programmazione. In particolare esse possono essere catalogate comesegue

• Metriche di Analisi, utili per consentire al management di monitorare econtrollare Costi, Scheduling e Qualità. Ad esempio

– Function Points : Calcolano il numero di funzionalità di un prodottoa partire dalle sue specifiche. Sono usate per valutare la produttività diun programmatore e stimare i costi del software da realizzare.

• Metriche di Design, ad esempio

– Complessità Ciclomatica(CC) : Misura il numero di cammini indi-pendenti in un metodo, legata al numero di condizioni if-then-else oswitch in esso presenti. Più il valore è alto, maggiore sarà lo sforzoper effettuare testing e debug sul codice.

– Lack of cohesion in Methods5 (LCOM): Misura il numero di disgiun-zioni tra i vari metodi locali. Una disgiunzione può essere ad esempiola non intersezione tra i metodi, che si verifica quando ad esempio duemetodi modificano una instanza comune. Maggiore è il suo valoreminore è la coesione presente in una classe.

3ISO-IEC 9126-34ISO-IEC 9126-45Proposta da Chidamber e Kemerer

8

• Metriche relative al Codice sorgente, come ad esempio:

– Lines of Code : Misura la lunghezza di un programma basandosi sulnumero di righe di codice, dove per riga di codice si intende6 una rigadi testo di un programma che non sia bianca o un commento.

– Number of Class: Misura il numero di classi presenti nel programma.E’ un indicatore della dimensione del software

– Number of Method: Misura il numero medio dei metodi per classe.Ogni classe deve avere un buon numero di metodi, ma non deve essereeccessivo.

• Metriche di Testing, utili nella fase di Testing e Debugging, come ad esem-pio:

– Percentuale di attributi pubblici o protetti, grazie alla quale è possi-bile tenere sotto controllo il coupling.

– Number of children7, misura il numero di sottoclassi di una super-classe. Al crescere di quest valore, cresce la quantità di test necessari.

– Depth of Inheritance Three, Rappresenza la distanza massima di unnodo (una classe) dalla radice dell’albero rappresentante la strutturaereditaria. Maggiore è la profondita della classe nella gerarchia, mag-giore è il numero di metodi che essa può ereditare e più difficile saràl’attività di Testing.

– Instability8(I) : Calcola lo sforzo che bisogna applicare per cambiareil package senza conseguenze per gli altri pacchetti. Viene calcolatacomeI = Ce

Ca+Cedove Ce rappresenta la dipendenza del package rispetto

ai package esterni e Ca rappresenza la dipendenda dei package esterniverso quello considerato. I valori spaziano tra 0.0 e 1.0 : Il valore 0.0indica massima stabilità del package, mentre 1.0 massima instabilità.

Le metriche appena citate fanno riferimento al modello previsto dalla norma-tiva per quanto concerne il modello di Qualità Interna ed Esterna: in particolareesse si riferiscono alle caratteristiche di Funzionalità, Manutenibilità e Porta-bilità del prodotto Software.

Per poter effettuare una misurazione chiara, precisa ma soprattutto organizzatasi può operare secondo il modello Paradigma Goal-Question-Metric : Si fissano

6Esistono varie definizioni a riguardo, quella proposta è quella più accettata7Proposta da Chidamber e Kemerer8Proposta da Robert C.Martin

9

gli obiettivi che si vogliono perseguire, e a partire da questi si derivano ( attraversole Questions ) i dati che permettono di raggiungere gli obiettivi. Infine si defini-sce uno schema di riferimento per interpretare i dati rilevati rispetto agli obiettivifissati. Questo modo di operare non è solo riferito al Software vero e proprio,ma può essere utilizzato anche per migliorare il processo di sviluppo con il qualequest’ultimo viene realizzato o ancora valutare la qualità delle risorse utilizzate.In generale, il miglioramento di una metrica può comportare uno stravolgimentodi un’altra metrica : se si vuole ad esempio organizzare il il codice di una classe,eliminando metodi lunghi e corposi, si può optare per una spartizione di responsa-bilità creando varie sotto funzioni ad hoc. Ciò consente da un lato di migliorare lerighe di codice per metodo, e quindi la leggibilità e comprensibilità, ma dall’altrosi va a peggiorare il numero di chiamate a funzioni del programma.

10

Capitolo 2

Refactoring

2.1 IntroduzioneLa manutenzione del software è una tra le fasi più importanti del ciclo di vita delsoftware.

Figura 2.1: Ciclo sviluppo software - Modello Waterfall

In questa fase si attuano dei processi di modifica dopo il rilascio del software alfine di :

• Migliorare le prestazioni.

• Correggere bug e malfunzionamenti non prima rilevati.

• Estendere delle funzionalità per adattarle ai nuovi bisogni degli utenti.

11

Senza questa fase il software è soggetto a deterioramento, fino a diventareLegacy. In seguito a studi empirici basati inizialmente sull’osservazione dell’evo-luzione di 4 versioni successive di un S.O. IBM, Lehman e Belady hanno propostodelle leggi proprio in merito. In particolare di queste leggi si ricorda:

• Modifiche continue : Un sistema deve necessariamente cambiare, o diven-terà progressivamente inutile.

• Complessità crescente : Quando un sistema viene modificato, la sua strut-tura si deteriora: per evitare ciò bisogna investire sulla manutenzione pre-ventiva.

Ed è proprio su questi ultimi aspetti che la Manutenzione basa le proprie fonda-menta, diventando il pilastro quasi principale per la realizzazione del software.

2.2 RefactoringL’intervento di Refactoring consiste nel miglioramento del codice e del designdei sistemi Object-Oriented al fine di migliorare il codice in termini di qualità ein termini di difficoltà nella manutenzione. Esso consiste nella ristrutturazione enella pulizia del codice sorgente del prodotto software al fine di:

• Migliorare il design del software.

• Rendere il codice più comprensibile.

• Dare un supporto nella ricerca di bug.

• Dare un supporto a sviluppare codice molto più velocemente.

L’ingegnere britannico Martin Fowler, considerato uno tra i massimi esponen-ti nella progettazione di software Object-Oriented, propone nel suo libro1 duedefinizioni differenti del termine, a seconda del contesto in cui viene usato:

Refactoring (noun): a change made to the internal structure ofsoftware to make it easier to understand and cheaper to modify withoutchangin its observable behaviour

Refactoring (verb): to restructure software by applying a series ofrefactorings without changing its observable behavior.

In ogni caso, l’attività di Refactoring consiste nella rimozione dei cosiddetti BadSmells Code, o anche più semplicemente detti Code Smells.

1Riferimento Bibliografico [1]

12

2.3 Bad Smells CodeCon il termine Bad Smells Code si fa riferimento a tutti quei problemi di designdel codice, i quali provocano deterioramento o scarse prestazioni del software.Essi possono essere catalogati in 5 aree:

• Bloaters : Si tratta di codici, metodi e classi che tendono ad aumentare lapropria dimensione. Esempi di bloater possono essere:

– Metodi Lunghi : metodi che contengono molte righe di codice. Unpossibile pattern applicabile è l’ estrazione di metodi: si identifica-no le varie parti che compongono un grosso problema ( inteso comemetodo ) e lo si scompone in tanti sotto problemi. È inoltre possibileapplicare la sostituzione di un metodo con un oggetto, rendendo lesue variabili interne come attributi di una classe e organizzandolo invari sotto metodi.

– Classi molto grandi: classi che contengono molti attributi e metodi.Un possibile pattern applicabile è l’estrazione di una sotto classe odi un’ interfaccia, quest’ultima applicabile se è necessario avere unalista di operazione e comportamenti comuni a varie classi, o se si vuoledescrivere al meglio le operazioni che la classe offre.

– Data Clumps: parti di codice che contengono gruppi di variabili iden-tiche tra loro. Un possibile pattern applicabile è l’estrazione di unaclasse, così da incapsularli all’interno di una struttura dati e utilizzabiliin varie situazioni senza duplicazioni.

– Lunga lista di Parametri : metodi che accettano in ingresso una lun-ga lista di valori. Ciò si verifica maggiormente quando abbiamo unaserie di algoritmi diversi tra loro posti all’interno di uno stesso meto-do. Se i valori presi in input si riferiscono ad una classe, o a classidiverse, è possibile sostituire la lista di parametri con chiamate allaclasse in questione per ottenere i valori desiderati. Se invece i valorisono tutti disgiunti tra loro, è possibile optare ad una realizzazione diuna classe dati , così da passare al metodo oggetto di Refactoring ilsolo riferimento all’istanza della classe.

• Object-Orientation Abuser : Si tratta di quelle procedure che rispettano inmaniera incompleta o scorretta il paradigma della programmazione objectoriented.

– Classi alternative con differenti interfacce : due o più classi esibi-scono lo stesso identico comportamento ma hanno metodi con nomen-clatura differenti. Un pattern possibile è quello dell’estrazione di una

13

super classe, e definire le classi in questione come sotto classi. In que-sto modo si crea una relazione di Generalizzazione-Specializzazione,e le classi ereditarie adotteranno la stessa nomenclatura per quantoriguarda metodi e variabili comuni.

– Switch statements : quando in uno o più metodi sono utilizzati se-quenze di if-then-else o del costrutto switch in maniera massiccia. Perisolare gli switch si può optare per una soluzione Polimorfa, ad esem-pio utilizzando il Pattern adatto al contesto. Ciò induce ad avere unamigliore organizzazione nel codice, ma non sempre si traduce nellasoluzione migliore.

– Variabili temporanee: variabili che mantengono il loro valore solo inalcune circostanze ( ad esempio utilizzate solo all’interno di un metodo). Spesso vengono utilizzate quando bisogna effettuare calcoli previstidall’algoritmo, o quando vengono richiesti numerosi input. Un patternpossibile è quello dell’estrazione di una classe, formata da variabilitemporanee che diventano attributi e tutti i metodi che le utilizzanodiventeranno metodi della classe.

• Change Preventers : Si tratta di codici che ostacolano la modifica o l’ulte-riore sviluppo del software.

– Cambiamenti sparsi: quando cambiamenti ad una classe comporta-no cambiamenti in altre classi. Una possibile tecnica è quella di Spo-stare il metodo e attributi appena creati anche alle altre classi chenecessitano di tale cambiamento.

• Dispensables : Si tratta di un qualcosa di inutile e non necessario la cuiassenza avrebbe reso il codice molto più pulito ed efficiente.

– Dead Code: variabili, parametri o attributi non più utilizzati, solita-mente perchè obsoleti. Spesso succede quando nella fase di manuten-zione si è svolto un cambiamento o un miglioramento di una determi-nata porzione di codice, tralasciando il vecchio codice. Quello che sipuò fare è rimuovere ciò che non è più necessario , o nel caso di pa-rametri di un metodo non più utilizzati, Rimuovere i soli parametriin questione.

– Codici duplicati : quando due o più frangenti di codice sono prati-camente uguali. Ciò capita maggiormente quando vi sono più pro-grammatori che lavorano sullo stesso progetto allo stesso momento,senza sincronizzarsi sul lavoro fatto. Se il codice duplicato si trova

14

all’interno della stessa classe, si può estrarre il metodo e farlo richia-mare dalle porzioni di codici che lo utilizzano. Se invece i codici nonsono propriamente duplicati, ma portano allo stesso risultato, si puòoptare per una sostituzione di algoritmo scegliendo quale tra loro è ilmigliore.

– Classi, metodi e attributi non utilizzati : si verifica maggiormentequando il codice viene creato per un determinato scopo ma poi abban-donato. Se effettivamente la classe non serve più, è possibile prose-guire con la sua eliminazione totale o ,se servono solo pochi metodi,proseguire con l’eliminazione di metodi e/o attributi non necessari.

• Couplers : Si tratta di un gruppo di codici che contribuiscono ad un ecces-sivo accoppiamento tra classi.

– Middle Man : quando una classe esegue azioni delegandole ad unaltra classe. Il pattern applicabile è quello della Rimozione MiddleMan : si eliminano i metodi deleganti e si forzano le classi ad eseguirel’azione desiderata in maniera diretta.

– Feature Envy : quando un metdo accede a dati un altro oggetto senzapermessi. Ciò si verifica maggiormente quando si effettua uno sposta-mento di metodi o spostamento di attributi da una classe all’altra.Si può spostare il metodo che richiama gli attributi dell’altra classese esso può effettivamente appartenere a quest’ultima.

15

2.4 Refactoring e gli IDEOggi giorno l’attività di Refactoring è ben supportata dagli IDE, ovvero gli am-bienti di sviluppo integrati, che rendono allo sviluppatore questa attività molto piùsemplice, supportandolo con una serie di teniche già preconfigurate. Lo svilup-po futuro degli IDE viaggia nella direzione di automatizzare maggiormente talimeccanismi, senza più l’ausilio umano.

2.4.1 EclipseEclipe è un IDE multi linguaggio e multi piattaforma sviluppato dalla EclipseFoundation formata da grandi aziende di spicco quali IBM che, tra le varie carat-teristiche, vede un pieno supporto alle tecniche di Refactoring più comuni. Con-siderando l’ultima versione, Ecplise Neon 4.6.0

Menù Refactoring Eclipse

Il menù riportato a fianco eofferto da Eclipe offre sva-riate tecniche di refactring"automatico", quali :

• Rinominare un meto-do;

• Spostare un metododa una classe all’altra;

• Estrarre classi;

• Estrarre metodi;

• Creare metodi inline;

• Push down e Pull up;

• Cambiare la firma diun metodo;

L’applicazione di queste tecniche avviene mediante un interfaccia userfriendly,che guida il programmatore nella loro attuazione e che, seppur in maniera auto-

16

matica, devono rispettare determinate norme e standard al fine di applicarle nelmiglior modo possibile.

2.4.2 Visual StudioVisual Studio è un ambiente di sviluppo progettato da Microsoft, multi linguaggioe multi piattaforma, che permette la realizzazione di software sia desktop chemobile.

Nella release del 2010, Microsoft ha aggiunto la possibilità di eseguire tecni-che di Refactoring come Extract Interface, Remove Parameters e Extract Methodsemplicemente selezionando la porzione di codice desiderata e scegliendo, dalmenù a tendina mostrato in Figura2.2, la tecnica desiderata. Rispetto ad Eclipse,Visual studio offre un numero minore di tecniche attuabili, in compenso mantie-ne un’interfaccia grafica per supportare il programmatore nella loro realizzazione.Dalle ultime release, in particolare considerando Visual Studio 2015, Microsoft haaccorpato tali tecniche nelle Quick Actions, ovvero azioni rapide che l’ambienteconsiglia di effettuare durante lo sviluppo del software, aggiungendone svariatein più rispetto alla versione 2010. In questo modo il programmatore viene quasinell’immediato avvisato della miglioria che può attuare, e quindi della notificatodella presenza di un Bad Smell nel codice mentre Eclipse no, lasciando così tuttonelle mani del programmatore.

Figura 2.2: Menù Visual Studio 2008

17

Capitolo 3

Applicazione Refactoring : Esempionoleggio Film

3.1 IntroduzioneIl codice che si vuole analizzare e su cui si adotteranno semplici tecniche di Re-factoring consiste nella gestione di negozio di “Noleggio film”. Il programmaconsiste nell’interazione del client con il server del noleggio tramite la tecnologiamiddleware RMI. Il client riceve dal server una lista di film disponibili e quest’ul-timo , dopo la scelta del client, ne elabora il conto finale.Le classi del progetto sono suddivise per package:

• Dati Astratti:

– Movie, che rappresenta il dato vero e proprio su cui si basa l’interoprogramma

– Noleggio,attraverso il quale si associa il Film noleggiato al numero digiorni di noleggio

• Client:

– Client, codice che permette l’interazione con l’utente

• Interfaccia:

– INoleggio, codice racchiude tutte le funzioni svolte dal Server

• Server:

– ServerNoleggio, il quale racchiude le funzonalità proprie del program-ma considerato

18

3.2 EsecuzioneIl programma va avviato tramite riga di comando. La prima classe ad essere av-viata è il server, il quale caricherà tutti i film disponibili per essere noleggiati eregistrerà un suo riferimento come oggetto remoto sul RMI Registry. Figura3.1

Figura 3.1: Avvio Server

La seconda classe ad essere avviata è il client, il quale si mette alla ricercadell’oggetto remoto "Server",salva un riferimento all’oggetto remoto e richiede lalista dei film da lui offerti. Figura3.2

19

Figura 3.2: Avvio Client

Dopodichè inizia l’interazione con l’utente. Quest’ultimo sceglie, tra una se-rie di titoli, quello che più gli interessa e solo dopo aver inserito il carattere 0, ilserver verrà contattato per richiedere il conto finale.

Figura 3.3: Avvio Client

20

3.3 Analisi pre-Refactoring

3.3.1 CodePro ToolLo strumento utilizzato per l’analisi delle metriche di qualità del software è Co-dePro.Si tratta di un plug-in per Eclipse offerto da Google allo scopo di aiutare losviluppatore nella correzione del codice, dando indicazioni su dove si può agireper ridurre errori e numero di vulnerabilità presenti. Esso è in grado di rilevare unnotevole numero di metriche utili tra cui :

• Metriche dimensionali

• Metriche di ereditarietà

• Metriche riguardanti la Complessità Ciclomatica

• Metriche riguardanti la documentazione

Il calcolo avviene in maniera completamente automatica e può essere eseguitotramite il suo menù di contesto. Per ogni metrica, CodePro offre oltre i valori mi-surati anche il significato della metrica considerata; è inoltre possibile porre dellesoglie particolari in base all’obiettivo prefissato, così da avere subito riscontro sultipo di metrica violata e quindi di un cattivo comportamento da parte del software.La sua interfaccia è mostrata in Figura3.4, la quale si presenta semplice e chiara,mostrando in rosso le metriche che sono state violate secondo i valori standard giàprefissati.

21

Figura 3.4: Interfaccia CodePro

Nel caso in esame, è possibile vedere che le violazioni presenti nel programmasono:

• Average Block Depth : ovvero la media della profondità di ogni blocco permetodo.

• Average Cyclomatic Complexity (CC) : ovvero la media della complessitàciclomatica di ogni metodo.

• Average Lines Of Code per method (LOC) : ovvero la media del numeroli righe di codice per metodo. Mantenere un numero basso di righe di co-dice per metodo migliora l’organizzazione e la leggibilità, nonchè la suamodificabilità, ma tende a far crescere l’albero delle chiamate

Per quanto riguarda tutte le altre metriche non violate secondo CodePro, si vedein particolare:

• Efferent Couplings rappresenta un indicatore di dipendenza delle classi diun package verso l’esterno. Rappresenta quindi un indicatore di dipendenzadi un package verso l’esterno.

22

• Afferent Couplings rappresenta un indicatore di dipendenza delle classiesterne da una classe in un altro package. Rappresenta quindi un indicatoredi responsabilità del package.

• Weighted Methods rappresenta la somma di tutte le complessità di tutti i me-todi di una classe. E’ un indicatore di quanto sforzo è richiesto per manteree sviluppare una particolare classe. Un valore alto corrisponde ad indica-re una classe molto complessa, e di conseguenza un duro lavoro per il suosviluppo e riuso. E’ consigliato attestare tale valore al di sotto di 50.

• Abstractness rappresenta la percentuale di classi astratte ( comprese le in-terfacce ) e classi concrete che appartengono al progetto analizzato.

• Comments Ratio rappresenta la percentuale di commenti nel progetto. E’preferibile avere un valore alto in quanto aiuta nella comprensione del co-dice.

Lo scopo di questa Analisi, con conseguenti applicazioni di semplici tecnichedi Refactoring, sarà quello di raggiungere un valore basso di linee di codice permetodo e quello di ridurre la complessità ciclomatica: in questo modo si renderàil codice più pulito, organizzato e lineare.

3.3.2 Applicazione RefactoringSoffermando l’attenzione su quest’ultima [Figura3.5], si può constatare come laclasse Client abbia il valore più alto in assoluto di righe di codice per metodo.Analizzando il codice della classe Client

Figura 3.5: Average LOC

1 p u b l i c c l a s s C l i e n t {23 p u b l i c s t a t i c vo id main ( S t r i n g a r g s [ ] ) throws RemoteExcept ion

, NotBoundExcept ion {4 R e g i s t r y r e g = L o c a t e R e g i s t r y . g e t R e g i s t r y ( 8 0 0 0 ) ;

23

5 I N o l e g g i o n o l e g g i o s h o p = ( I N o l e g g i o ) r e g . lookup ( " Nolegg io ") ;

6 Vector < S t r i n g > _ l i s t a = new Vector < S t r i n g > ( ) ;78 _ l i s t a = n o l e g g i o s h o p . r i c h i e d i L i s t a ( ) ;9 Enumera t ion < S t r i n g > l i s t a = _ l i s t a . e l e m e n t s ( ) ;

10 whi le ( l i s t a . hasMoreElements ( ) )11 System . o u t . p r i n t l n ( l i s t a . n e x t E l e m e n t ( ) ) ;12 t r y {13 B u f f e r e d R e a d e r d i s = new B u f f e r e d R e a d e r ( new

I n p u t S t r e a m R e a d e r ( System . i n ) ) ;14 i n t s c e l t a =1 ;15 i n t days =0;16 System . o u t . p r i n t l n ( " Premi 0 p e r t e r m i n a r e " ) ;17 System . o u t . p r i n t l n ( " S c e g l i f i l m da n o l e g g i a r e . . . " ) ;18 s c e l t a = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;19 whi le ( s c e l t a ! = 0 ) {20 System . o u t . p r i n t l n ( " Qu an t i g i o r n i ? " ) ;21 days = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;22 t r y {23 n o l e g g i o s h o p . n o l e g g i a ( _ l i s t a . g e t ( ( s c e l t a −1) ) ,

days ) ;24 System . o u t . p r i n t l n ( " R i c h i e s t a p e r "+ _ l i s t a . g e t (

s c e l t a −1)+" e f f e t t u a t a con s u c c e s s o " ) ;25 } catch ( Ar ray IndexOutOfBoundsExcep t ion |

NumberFormatExcept ion e ) {26 System . o u t . p r i n t l n ( "ATTENZIONE , FILM NON NELLA

LISTA" ) ;27 } f i n a l l y {28 System . o u t . p r i n t l n ( " S c e g l i f i l m da n o l e g g i a r e . . . "

) ;29 s c e l t a = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;30 }31 }32 } catch ( IOExcep t ion e ) {33 e . p r i n t S t a c k T r a c e ( ) ;34 }35 S t r i n g e s i t o = n o l e g g i o s h o p . r i c h i e d i C o n t o ( ) ;36 System . o u t . p r i n t l n ( e s i t o ) ;3738 }

Codice 3.1: Codice Client

24

Si nota l’esistenza di un unico metodo, ovvero il metodo main, il quale risultaessere ricco di funzionalità che potrebbero essere esportate in differenti metodi.Potendo suddividere il codice in 3 macro aree:

• Stampa della lista popolata tramite il metodo richiediLista() dell’interfacciaINoleggio

• La scelta dell’utente dei film che vuole noleggiare, caratterizzata da unwhile(scelta!=0) e da una serie di righe di codice utili per l’interazioneUtente-Software

• Richiesta del conto finale tramite richiediConto() dell’interfaccia INoleggio

La prima tecnica di refactoring che viene naturale adottare è Extract Method.Tale tecnica consiste nel estrarre una porzione di codice da un metodo per crea-re un metodo a se stante, consentendone il risutilizzo. Ciò consente di avere unprogramma più pulito con l’assenza di codice duplicato, ma aumenta al contempoil numero delle chiamate a sottoprogramma. Utilizzando Eclipse la tecnica vieneapplicata automaticamente, andando a selezionare il codice che si vuole estrarre

Figura 3.6: Menù contestuale di Eclipse

Pigiando sulla voce Extract Method si aprirà una finestra [figura suc-cessiva] in cui è possibile scegliere il nome del metodo, la visibilità, i parame-tri passati; inoltre viene visualizzata una piccola preview della firma del metodoestratto.

25

Figura 3.7: Finestra Extract Method Eclipse

Ottenendo come risultato i seguenti metodi estratti sempre appartenenti allaclasse Client

1 p r i v a t e s t a t i c vo id n o l e g g i a ( I N o l e g g i o n o l e g g i o s h o p , Vector <S t r i n g > _ l i s t a ) {

2 t r y {3 B u f f e r e d R e a d e r d i s = new B u f f e r e d R e a d e r ( new

I n p u t S t r e a m R e a d e r ( System . i n ) ) ;4 i n t s c e l t a =1 ;5 i n t days =0;6 System . o u t . p r i n t l n ( " Premi 0 p e r t e r m i n a r e " ) ;

26

7 System . o u t . p r i n t l n ( " S c e g l i f i l m da n o l e g g i a r e . . . " ) ;8 s c e l t a = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;9 whi le ( s c e l t a ! = 0 ) {

10 System . o u t . p r i n t l n ( " Qu an t i g i o r n i ? " ) ;11 days = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;12 t r y {13 n o l e g g i o s h o p . n o l e g g i a ( _ l i s t a . g e t ( ( s c e l t a −1) ) ,

days ) ;14 System . o u t . p r i n t l n ( " R i c h i e s t a p e r "+ _ l i s t a . g e t (

s c e l t a −1)+" e f f e t t u a t a con s u c c e s s o " ) ;15 } catch ( Ar ray IndexOutOfBoundsExcep t ion |

NumberFormatExcept ion e ) {16 System . o u t . p r i n t l n ( "ATTENZIONE , FILM NON NELLA

LISTA" ) ;17 } f i n a l l y {18 System . o u t . p r i n t l n ( " S c e g l i f i l m da n o l e g g i a r e . . . "

) ;19 s c e l t a = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;20 }21 }22 } catch ( IOExcep t ion e ) {23 e . p r i n t S t a c k T r a c e ( ) ;24 }25 }2627 p r i v a t e s t a t i c vo id s t a m p a L i s t a ( Vector < S t r i n g > _ l i s t a ) {28 Enumera t ion < S t r i n g > l i s t a = _ l i s t a . e l e m e n t s ( ) ;29 whi le ( l i s t a . hasMoreElements ( ) )30 System . o u t . p r i n t l n ( l i s t a . n e x t E l e m e n t ( ) ) ;31 }

Codice 3.2: Metodi Estratti classe Client

Per quanto riguarda la richiesta del conto finale, piuttosto che estrarre il metodo,è possibile trasformarlo Inline, ovvero riportarlo su unica riga di codice, elimi-nando in questo modo la variabile temporanea String Esito.

richiediConto prima

richiediConto dopo

A questo punto il metodo main della classe Client diventa molto più semplice ecomprensibile:

27

1 p u b l i c c l a s s C l i e n t {23 p u b l i c s t a t i c vo id main ( S t r i n g a r g s [ ] ) throws RemoteExcept ion

, NotBoundExcept ion {4 R e g i s t r y r e g = L o c a t e R e g i s t r y . g e t R e g i s t r y ( 8 0 0 0 ) ;5 I N o l e g g i o n o l e g g i o s h o p = ( I N o l e g g i o ) r e g . lookup ( " Nolegg io "

) ;6 Vector < S t r i n g > _ l i s t a = new Vector < S t r i n g > ( ) ;7 _ l i s t a = n o l e g g i o s h o p . r i c h i e d i L i s t a ( ) ;8 s t a m p a L i s t a ( _ l i s t a ) ;9 n o l e g g i a ( n o l e g g i o s h o p , _ l i s t a ) ;

10 System . o u t . p r i n t l n ( n o l e g g i o s h o p . r i c h i e d i C o n t o ( ) ) ;1112 }1314 }

Codice 3.3: Codice Client Finale

Continuando l’analisi sulla metrica mostarto in Figura3.5 è possibile notarecome anche il package server abbia molte righe di codice per metodo, attestandoun valor medio pari a 12.50. Di seguito il codice Server

1 p u b l i c c l a s s S e r v e r N o l e g g i o ex tends U n i c a s t R e m o t e O b j e c timplements I N o l e g g i o {

23 p r i v a t e s t a t i c f i n a l long s e r i a l V e r s i o n U I D = 1L ;4 Vector <Movie > _ l i s t a F i l m ;5 Vector < Noleggio > _ l i s t a N o l e g g i a t i ;67 p u b l i c S e r v e r N o l e g g i o ( ) throws RemoteExcep t ion {8 super ( ) ;9 _ l i s t a F i l m = new Vector <Movie > ( ) ;

10 _ l i s t a N o l e g g i a t i = new Vector < Noleggio > ( ) ;1112 }1314 p u b l i c Vector < S t r i n g > r i c h i e d i L i s t a ( ) {15 Enumera t ion <Movie > l i s t a = _ l i s t a F i l m . e l e m e n t s ( ) ;16 Vector < S t r i n g > e l e n c o = new Vector < S t r i n g > ( ) ;17 whi le ( l i s t a . hasMoreElements ( ) ) {18 Movie f i l m = l i s t a . n e x t E l e m e n t ( ) ;19 e l e n c o . add ( f i l m . g e t T i t l e ( ) ) ;20 }21 re turn e l e n c o ;

28

22 }2324 p u b l i c boolean n o l e g g i a ( S t r i n g _f i lm , i n t days ) {25 Enumera t ion <Movie > l i s t a = _ l i s t a F i l m . e l e m e n t s ( ) ;26 whi le ( l i s t a . hasMoreElements ( ) ) {27 Movie f i l m = l i s t a . n e x t E l e m e n t ( ) ;28 i f ( f i l m . g e t T i t l e ( ) . e q u a l s ( _ f i l m ) ) {29 _ l i s t a N o l e g g i a t i . add (30 new Nolegg io ( new Movie ( f i l m . g e t T i t l e ( ) , f i l m .

g e t P r i c e C o d e ( ) ) , days ) ) ;31 re turn true ;32 }33 }34 re turn f a l s e ;35 }3637 p r i v a t e vo id a g g i u n g i F i l m ( S t r i n g _f i lm , i n t p r i c e C o d e ) {38 _ l i s t a F i l m . add ( new Movie ( _ f i lm , p r i c e C o d e ) ) ;39 }4041 p u b l i c S t r i n g r i c h i e d i C o n t o ( ) {42 double t o t a l A m o u n t = 0 ;43 i n t f r e q u e n t R e n t e r P o i n t s = 0 ;44 Enumera t ion < Noleggio > r e n t a l s = _ l i s t a N o l e g g i a t i . e l e m e n t s

( ) ;45 S t r i n g r e s u l t = " N o l e g g i a t o : \ n " ;46 whi le ( r e n t a l s . hasMoreElements ( ) ) {47 double th i sAmount = 0 ;48 Nolegg io each = r e n t a l s . n e x t E l e m e n t ( ) ;49 sw i t ch ( each . ge tMovie ( ) . g e t P r i c e C o d e ( ) ) {50 case Movie .REGULAR:51 th i sAmount +=2;52 i f ( each . ge tDaysRen ted ( ) >2) {53 th i sAmount += ( each . ge tDaysRen ted ( ) −2) ;54 th i sAmount ∗= 1 . 5 ;55 }56 break ;57 case Movie . NEW_RELEASE:58 th i sAmount += each . ge tDaysRen ted ( ) ∗3 ;59 break ;6061 case Movie . CHILDRENS :62 th i sAmount + = 1 . 5 ;

29

63 i f ( each . ge tDaysRen ted ( ) >3) {64 th i sAmount += ( each . ge tDaysRen ted ( ) −3) ;65 th i sAmount ∗= 1 . 5 ;66 }67 break ;68 d e f a u l t :69 break ;70 }71 f r e q u e n t R e n t e r P o i n t s ++;72 i f ( ( each . getMovie ( ) . g e t P r i c e C o d e ( ) == Movie . NEW_RELEASE

) && each . ge tDaysRen ted ( ) >1) {73 f r e q u e n t R e n t e r P o i n t s ++;74 }75 r e s u l t += " \ t "+ each . ge tMovie ( ) . g e t T i t l e ( ) +" \ t "+ S t r i n g .

va lueOf ( ( th i sAmount ) ) +" \ n " ;76 t o t a l A m o u n t += th i sAmount ;77 }78 r e s u l t += " Cos to t o t a l e eu ro " + S t r i n g . va lueOf (

t o t a l A m o u n t ) + " \ n " ;79 r e s u l t += " Hai g u a d a g n a t o " + S t r i n g . va lueOf (

f r e q u e n t R e n t e r P o i n t s ) + " p u n t i f e d e l t a ’ " ;80 re turn r e s u l t ;8182 }8384 p u b l i c s t a t i c vo id main ( S t r i n g a r g s [ ] ) throws RemoteExcep t ion

{85 R e g i s t r y r e g = L o c a t e R e g i s t r y . c r e a t e R e g i s t r y ( 8 0 0 0 ) ;86 S e r v e r N o l e g g i o n o l e g g i o = new S e r v e r N o l e g g i o ( ) ;8788 n o l e g g i o . a g g i u n g i F i l m ( " Fi lm 1 " , 2 ) ;89 n o l e g g i o . a g g i u n g i F i l m ( " Fi lm 2 " , 1 ) ;90 n o l e g g i o . a g g i u n g i F i l m ( " Fi lm 3 " , 0 ) ;91 n o l e g g i o . a g g i u n g i F i l m ( " Fi lm 4 " , 2 ) ;92 n o l e g g i o . a g g i u n g i F i l m ( " Fi lm 5 " , 0 ) ;93 n o l e g g i o . a g g i u n g i F i l m ( " Fi lm 6 " , 1 ) ;9495 r e g . r e b i n d ( " Nolegg io " , n o l e g g i o ) ;96 System . o u t . p r i n t l n ( " ∗∗∗∗∗∗∗∗∗ S e r v e r Nolegg io a v v i a t o

∗∗∗∗∗∗∗∗∗ " ) ;97 }98 }

Codice 3.4: Codice Server

30

Anche in questo possiamo applicare la tecnica Extract Method per ridur-re il numero di righe di codice del metodo richiediConto() mostrato in [Codice3.4]Infatti tale metodo è formato da 2 parti:

• Calcolo del conto finale sulla base delle scelte effettuate dall’utente

• Calcolo dei punti fedeltà

Si procede allora all’estrazione dei metodi sia per ottenere l’ammontare di un filmnoleggiato e sia per i punti fedeltà: quest’ultimo può essere scritto in forma com-patta utilizzando una variabile booleana come se fosse una query e utilizzando laforma compatta dell’if, scritta direttamente come il "corpo" del return del meto-do. In questo modo si va a creare un metodo inline, ovvero un metodo il cuicorpo è formato dal solo return . Il metodo per richiedere l’ammontare di un filmpuò essere sottoposto ad un altra tecnica di refactoring, ovvero la Move Method:Tale tecnica consiste nel spostare il metodo da una classe all’altra. Questa tecni-ca viene utilizzata per fare chiarezza sulle responsabilità delle classi, soprattuttoquando ad esempio il metodo riferisce ad oggetti appartenenti ad un’altra classeche non è quella in cui è definito. In definitiva, piuttosto che applicare l’ExtractMethod, applicando il Move Method si dividono le responsabilità tra le varieclassi e si ottiene una maggior comprensibilità nella lettura del codice. Sposto ilmetodo ottieniPrezzo nella classe Noleggio e modifico richiediConto in Server-Noleggio che, piuttosto che avere il delegato, può far direttamente riferimento almetodo appena implementato. La stessa tecnica viene adottata anche per il meto-do getPoints() per i punti fedeltà, che viene spostato nella classe Noleggio. Anchein questo caso Eclipse ci da una mano, basta infatti selezionare il codice in que-stione e tramite il menù che si apre con il tasto destro e pigiare su "Move": unafinestra wizard guida nell’applicare tale tecnica in maniera veloce, senza doverriscrivere codice o fare copia e incolla. Di seguito il risultato ottenuto:

1 p u b l i c c l a s s Nolegg io {23 p r i v a t e Movie _movie ;4 p r i v a t e i n t _daysRen ted ;56 p u b l i c Nolegg io ( Movie movie , i n t days ) {7 super ( ) ;8 _movie=movie ;9 _daysRen ted = days ;

10 }1112 p u b l i c i n t ge tDaysRen ted ( ) {13 re turn _daysRen ted ;

31

14 }1516 p u b l i c Movie getMovie ( ) {17 re turn _movie ;18 }1920 p u b l i c double o t t i e n i P r e z z o ( ) {21 double r e s u l t =0 ;22 sw i t ch ( t h i s . ge tMovie ( ) . g e t P r i c e C o d e ( ) ) {23 case Movie .REGULAR:24 r e s u l t += 2 ;25 i f ( t h i s . ge tDaysRen ted ( ) > 2 )26 r e s u l t += ( t h i s . ge tDaysRen ted ( ) − 2) ∗ 1 . 5 ;27 break ;28 case Movie . NEW_RELEASE:29 r e s u l t += t h i s . ge tDaysRen ted ( ) ∗ 3 ;30 break ;31 case Movie . CHILDRENS :32 r e s u l t += 1 . 5 ;33 i f ( t h i s . ge tDaysRen ted ( ) > 3 )34 r e s u l t += ( t h i s . ge tDaysRen ted ( ) − 3) ∗ 1 . 5 ;35 break ;36 d e f a u l t :37 break ;38 }39 re turn r e s u l t ;40 }4142 p u b l i c i n t g e t P o i n t s ( ) {43 boolean e s i t o = ( ( getMovie ( ) . g e t P r i c e C o d e ( ) == Movie .

NEW_RELEASE) && getDaysRen ted ( ) > 1) ;44 re turn e s i t o ? 1 : 2 ;45 }4647 }

Codice 3.5: Codice Noleggio dopo il Move Method

Mentre richiediConto() della classe Server è diventato

1 p u b l i c S t r i n g r i c h i e d i C o n t o ( ) {2 double t o t a l A m o u n t = 0 ;3 i n t f r e q u e n t R e n t e r P o i n t s = 0 ;

32

4 Enumera t ion < Noleggio > r e n t a l s = _ l i s t a N o l e g g i a t i . e l e m e n t s( ) ;

5 S t r i n g r e s u l t = " N o l e g g i a t o : \ n " ;6 whi le ( r e n t a l s . hasMoreElements ( ) ) {7 double th i sAmount = 0 ;8 Nolegg io each = r e n t a l s . n e x t E l e m e n t ( ) ;9 th i sAmount = each . o t t i e n i P r e z z o ( ) ;

10 f r e q u e n t R e n t e r P o i n t s += each . g e t P o i n t s ( ) ;11 r e s u l t += " \ t " + each . ge tMovie ( ) . g e t T i t l e ( ) + " \ t " +

S t r i n g . va lueOf ( ( th i sAmount ) ) + " \ n " ;12 t o t a l A m o u n t += th i sAmount ;13 }14 r e s u l t += " Cos to t o t a l e eu ro " + S t r i n g . va lueOf (

t o t a l A m o u n t ) + " \ n " ;15 r e s u l t += " Hai g u a d a g n a t o " + S t r i n g . va lueOf (

f r e q u e n t R e n t e r P o i n t s ) + " p u n t i f e d e l t a ’ " ;16 re turn r e s u l t ;1718 }

Codice 3.6: Codice richiediConto classe Server

33

Effettuando nuovamente un analisi statica tramite CodePro è possibile notarequalche miglioramento dovunto all’attuazione di tali tecniche, semplici ma effica-ci. [Figura3.8]

Figura 3.8: Analisi CodePro dopo

In particolare si può notare come il valore Average Lines Of Code Per Methodsi sia abbassato di 1 punto, vedendo come peso maggiore sempre il codice dellaclasse Client ma che passa da 34.00 a 13.00.[Figura3.9]

Figura 3.9: Analisi LOC dopo

Per quanto riguarda la complessità ciclomatica, seppur passata da 2.00 a 1.75,

34

vede ancora delle violazioni. In particolare, si vede come il valore massimo siapassato dalla classe Server alla classe Noleggio, in quanto con il Move Method ilmetodo richiediPrezzo è passato a quest’ultima classe e con esso lo SWITCH chedecide il prezzo a seconda della tipologia.

Figura 3.10: Analisi CC prima

Figura 3.11: Analisi CC dopo

Per risolvere questa violazione è possibile adottare il Polimorfismo. Con il ter-mine Polimorfismo si intende la proprietà di una entità di assumere forme diversenel tempo il che, in termini di programmazione Object Oriented, significa che piùoggetti implementano la medesima interfaccia e a tempo di compilazione (LateBinding) viene richiamata la funzione giusta, riducendo significativamente il nu-mero di statements if-then-else o di switch-case presenti nel codice.Grazie a questo meccanismo è possibile utilizzare i Design Pattern al fine di or-ganizzare al meglio il codice sorgente e renderlo più comprensibile agli occhi dichi dovrà poi mettere mano per la manutenzione. Il Pattern che si vuole adottareè il Pattern State, un Design Pattern Comportamentale: esso consente ad un og-getto di cambiare il proprio comportamento a run-time in funzione dello stato incui si trova. Oltre che ridurre possibili duplicazioni di codice e il numero di sta-tements if-then-else o switch-case, il Pattern State consente di avere una maggiorflessibilità nella aggiunta di nuove classi che riferiscono tutte allo stesso tipo. Losvantaggio principale è appunto l’introduzioni di molte più classi nel progetto.

35

Figura 3.12: Pattern State

In questa struttura possiamo vedere tre entità fondamentali:

• Context : definisce una interfaccia di interesse per il cliente e mantiene unriferimento ad un ConcreteState che rappresenta lo stato corrente

• State : definisce un interfaccia di servizio comune a tutti i ConcreteStateche la implementano

• ConcreteState : definisce il comportamento vero e proprio dello stato cherappresenta

Tali entità possono essere ben viste nel programma qui presentato, in particolarmodo si può fare in modo che le varie tipologie di prezzi presenti nella classeMovie possano essere gestite come delle classi a sè stanti, quindi con un compor-tamento diverso a seconda della tipologia. Tutte però accomunate da una stessainterfaccia IPrezzo ( che fungerà da State in linea con il pattern utilizzato ) cheoffrirà un metodo polimorfo getPrice() e definito in ogni classe che rappresenteràuna tipologia di prezzo ( ovvero Concrete State ). Infine la classe Movie avrà unriferimento ad una tipologia di prezzo, definendo così l’entità Context del Pattern.Ricapitolando, volendo applicare tale pattern, le entità si applicheranno in talsenso:

• Movie sarà il Context

• IPrice sarà una interfaccia di servizio comune, ovvero lo State

• Tipologie di prezzo saranno i Concrete State che implementano l’interfac-cia IPrice

36

Prima di tutto, si può dare alla classe Movie la responsabilità dei metodi ot-tieniPrezzo() e getPoints() : tali metodi infatti si riferiscono al singolo film e nonal Noleggio. Essi verranno comunque richiamati tramite le istanze della classeNoleggio ma delegando il riferimento a Movie nel calcolo vero e proprio.

1 p u b l i c c l a s s Nolegg io {23 p r i v a t e Movie _movie ;4 p r i v a t e i n t _daysRen ted ;56 p u b l i c Nolegg io ( Movie movie , i n t days ) {7 super ( ) ;8 _movie=movie ;9 _daysRen ted = days ;

10 }1112 p u b l i c i n t ge tDaysRen ted ( ) {13 re turn _daysRen ted ;14 }1516 p u b l i c Movie getMovie ( ) {17 re turn _movie ;18 }1920 p u b l i c double o t t i e n i P r e z z o ( ) {21 re turn _movie . o t t i e n i P r e z z o ( _daysRen ted ) ;22 }2324 p u b l i c i n t g e t P o i n t s ( ) {25 re turn _movie . g e t P o i n t s ( _daysRen ted ) ;26 }2728 }

Codice 3.7: Codice Noleggio dopo

Per ricavare l’interfaccia IPrice, Eclipse mette a disposizione un piccolo toolche, una volta selezionato quale metodo sarà polimorfo, è in grado di crearlaautomaticamente.

37

Figura 3.13: Tool Eclipse Extract Interface

Definito lo State, si passa ora alla definizione delle entità concrete, ovvero iConcrete State. Nel programma che stiamo esaminando, sono presenti tre tipolo-gie di prezzo definite come static final nella classe Movie le quali diventerannole classi concrete che implementeranno i servizi forniti da IPrice : CHILDRENS,REGULAR, NEW_RELEASE. Di seguito i codici delle nuove tre classi

1 p u b l i c c l a s s C h i l d r e n P r i c e implements I P r i c e {23 p r i v a t e s t a t i c f i n a l long s e r i a l V e r s i o n U I D = 1L ;45 @Override6 p u b l i c i n t g e t P r i c e C o d e ( ) {7 re turn I P r i c e . CHILDRENS ;8 }

38

910 @Override11 p u b l i c double o t t i e n i P r e z z o ( i n t days ) {12 double r e s u l t = 1 . 5 ;13 i f ( days >3) r e s u l t += ( days −3) ∗ 1 . 5 ;14 re turn r e s u l t ;15 }1617 @Override18 p u b l i c i n t g e t F r e q u e n t R e n t e r P o i n t s ( i n t days ) {19 re turn 1 ;20 }2122 }

Codice 3.8: Codice ChildrenPrice

1 p u b l i c c l a s s NewReleasePr i ce implements I P r i c e {23 p r i v a t e s t a t i c f i n a l long s e r i a l V e r s i o n U I D = 1L ;45 @Override6 p u b l i c i n t g e t P r i c e C o d e ( ) {7 re turn I P r i c e . NEW_RELEASE;8 }9

10 @Override11 p u b l i c double o t t i e n i P r e z z o ( i n t days ) {12 double r e s u l t = days ∗ 3 ;13 re turn r e s u l t ;14 }1516 @Override17 p u b l i c i n t g e t F r e q u e n t R e n t e r P o i n t s ( i n t days ) {18 re turn ( days >1) ? 2 : 1 ;19 }2021 }

Codice 3.9: Codice NewReleasePrice

39

1 p u b l i c c l a s s R e g u l a r P r i c e C o d e implements I P r i c e {23 p r i v a t e s t a t i c f i n a l long s e r i a l V e r s i o n U I D = 1L ;45 @Override6 p u b l i c i n t g e t P r i c e C o d e ( ) {7 re turn I P r i c e .REGULAR;8 }9

10 @Override11 p u b l i c double o t t i e n i P r e z z o ( i n t daysRen ted ) {12 double r e s u l t = 2 ;13 i f ( daysRen ted > 2)14 r e s u l t += ( daysRen ted − 2) ∗ 1 . 5 ;15 re turn r e s u l t ;16 }1718 @Override19 p u b l i c i n t g e t F r e q u e n t R e n t e r P o i n t s ( i n t daysRen ted ) {20 re turn 1 ;21 }2223 }

Codice 3.10: Codice RegularPrice

Come si osserva, le tre classi che implementano IPrice definiscono i metodi a se-conda della loro natura. Ciò consente di evitare lo switch presente nel metodoottieniPrezzo() e di sostituirlo con una chiamata polimorfa tramite il riferimentoche la classe Movie dovrà presentare, sostiuendo l’attributo int _priceCode conIPrice _priceCode.

1 p u b l i c c l a s s Movie implements S e r i a l i z a b l e {23 p r i v a t e s t a t i c f i n a l long s e r i a l V e r s i o n U I D = 1L ;4 p r i v a t e S t r i n g _ t i t l e ;5 p r i v a t e I P r i c e _ p r i c e C o d e ;67 p u b l i c Movie ( S t r i n g t i t l e , i n t p r i c e C o d e ) {8 _ t i t l e = t i t l e ;9 s e t P r i c e C o d e ( p r i c e C o d e ) ;

10 }1112 p u b l i c i n t g e t P r i c e C o d e ( ) {

40

13 re turn _ p r i c e C o d e . g e t P r i c e C o d e ( ) ;14 }1516 p u b l i c S t r i n g g e t T i t l e ( ) {17 re turn _ t i t l e ;18 } ;192021 p u b l i c double o t t i e n i P r e z z o ( i n t days ) {22 re turn _ p r i c e C o d e . o t t i e n i P r e z z o ( days ) ;23 }2425 p u b l i c i n t g e t P o i n t s ( i n t days ) {26 re turn _ p r i c e C o d e . g e t F r e q u e n t R e n t e r P o i n t s ( days ) ;27 }28 p r i v a t e void s e t P r i c e C o d e ( i n t p r i c e C o d e ) {29 sw i t ch ( p r i c e C o d e ) {30 case I P r i c e . CHILDRENS :31 _ p r i c e C o d e = new C h i l d r e n P r i c e ( ) ;32 break ;33 case I P r i c e . NEW_RELEASE:34 _ p r i c e C o d e = new NewReleasePr i ce ( ) ;35 break ;36 case I P r i c e .REGULAR:37 _ p r i c e C o d e = new R e g u l a r P r i c e ( ) ;38 break ;39 d e f a u l t :40 break ;41 }42 }4344 }

Codice 3.11: Codice Movie

Un ulteriore miglioria che è possibile attuare consiste nella sostituzione di al-goritmo in un metodo. Tale tecnica consiste nel riformulare un metodo al fine direnderlo più semplice e comprensibile, cercando di migliorare allo stesso tempole performance. Considerando il programma in esame, la sostituzione di algorit-mo più semplice che si può attuare sta nel metodo noleggia della classe Client enoleggia della classe ServerNoleggio. Nel primo si nota una frequente chiamataremota al metodo noleggia di ServerNoleggio e quest’ultimo, ogni volta che vienerichiamato, va alla ricerca del film che si vuole noleggiare anche se sicuramente

41

presente nella lista 1. Il nuovo metodo noleggia della classe Client può essereriscritto in questo modo

1 p r i v a t e s t a t i c vo id n o l e g g i a ( I N o l e g g i o n o l e g g i o s h o p , Vector <S t r i n g > _ l i s t a ) {

2 t r y {3 B u f f e r e d R e a d e r d i s = new B u f f e r e d R e a d e r ( new

I n p u t S t r e a m R e a d e r ( System . i n ) ) ;4 i n t s c e l t a =1 ;5 i n t days =0;6 System . o u t . p r i n t l n ( " Premi 0 p e r t e r m i n a r e " ) ;7 System . o u t . p r i n t l n ( " S c e g l i f i l m da n o l e g g i a r e . . . " ) ;8 s c e l t a = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;9 whi le ( s c e l t a ! = 0 ) {

10 System . o u t . p r i n t l n ( " Qu an t i g i o r n i ? " ) ;11 days = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;12 a g g i u n t a F i l m ( _ l i s t a , days , s c e l t a ) ;13 System . o u t . p r i n t l n ( " S c e g l i f i l m da n o l e g g i a r e . . . " ) ;14 s c e l t a = I n t e g e r . p a r s e I n t ( d i s . r e a d L i n e ( ) ) ;15 }16 n o l e g g i o s h o p . n o l e g g i a ( s c e l t e , tempo ) ;17 } ca tch ( IOExcep t ion e ) {18 e . p r i n t S t a c k T r a c e ( ) ;19 }20 }2122 p r i v a t e s t a t i c vo id a g g i u n t a F i l m ( Vector < S t r i n g > _ l i s t a , i n t days

, i n t s c e l t a ) throws IOExcep t i on {23 i f ( ( s c e l t a −1)<= _ l i s t a . s i z e ( ) ) {24 s c e l t e . add ( s c e l t a −1) ;25 tempo . add ( days ) ;26 System . o u t . p r i n t l n ( " R i c h i e s t a p e r "+ _ l i s t a . g e t ( s c e l t a −1)+

" e f f e t t u a t a con s u c c e s s o " ) ;27 } e l s e {28 System . o u t . p r i n t l n ( "ATTENZIONE , FILM NON NELLA LISTA" ) ;29 }30 }

Codice 3.12: Codice noleggia() Client

1Il blocco try-catch presente in noleggia di Client solleva una eccezione nel ca-so che il film scelto non sia presente nel catalogo attraverso un eccezione di tipoArrayIndexOutOfBoundsException .

42

mentre quello della classe ServerNoleggio

1 p u b l i c vo id n o l e g g i a ( Vector < I n t e g e r > _f i lm , Vector < I n t e g e r > days) {

2 f o r ( i n t i =0 ; i < _ f i l m . s i z e ( ) ; i ++)3 _ l i s t a N o l e g g i a t i . addElement ( new Nolegg io ( _ l i s t a F i l m . g e t (

_ f i l m . g e t ( i ) ) , days . g e t ( i ) ) ) ;4 }

Codice 3.13: Codice noleggia() Server

Anche se il metodo noleggia() di Client ora è scomposto in due metodi, si ha unmiglioramento in quanto il numero di chiamate remote verso il Server è diminuitodrasticamente, da n chiamate a 1 unica chiamata, mentre lato Server non abbiamopiù quel ciclo while con al suo interno un if per verificare l’esistenza o meno delfilm che si vuole noleggiare, ma abbiamo un for che non fa altro che aggiungere ifilm sulla base degli indici passati tramite il vettore di interi film.

43

3.4 Analisi post-RefactoringEseguendo nuovamente CodePro dopo aver apportato queste notifiche, si evincela situazione in Figura3.14.

Figura 3.14: Analisi post-Refactoring

Comparando gli ultimi risultati ottenuti con quelli mostrati in Figura3.8 e in par-ticolare con l’analisi fatta in partenza mostrata in Figura3.4, si evincono dei mi-glioramenti su tutte le metriche analizzate. In particolare vediamo che :

• La complessità ciclomatica media è passata da un valore iniziale di 2.00 adun valore 1.38

• Il numero medio di righe di codice per metodo è passato da un valoreiniziare 8.31 ad un valore 5.27

Partendo dalla complessità ciclomatica, e confrontando i valori ottenuti dopo ilRefactoring con quelli valutati in partenza mostrati in Figura3.10Si può notare un netto miglioramento, in quanto i valori medi divisi per package

44

sono dimezzati, tranne per il package adt che vede un aumento da 1.00 a 1.35dovuto al polimorfismo e per come si è costruito il metodo setPrice() mostrato nelCodice3.11Per quanto riguarda il numero medio di righe di codice, se si confronta questoultimo risultato con i valori misurati in partenza mostrati in Figura3.5

Si nota come il valore globale passa dall’essere 8.31 a 5.27, risultato ottenuto so-prattutto grazie alla tecnica Extract Method e, per quanto riguarda i singolipackage, si nota un miglioramento netto nel package Client che passa da 34 a10.75, mentre il package server passa da 12.50 a 8.33.Tuttavia è bene sottolineare anche se i valori di Complessità Ciclomatica e LCOMsiano migliorati, altre metriche sono cresciute e andate a peggiorare. In particolarenotiamo un peggioramento dell’ Efferent Coupling e Afferent Coupling che pas-sano rispettivamente da 4 a 8 e da 2 a 6 : ciò si traduce in una forte dipendenda deivari package verso l’esterno, quindi verso altri package del progetto. Tali valorifanno però migliorare, seppur in maniera minima, l’instabilità del progetto, chepassa da 0.66 a 0.57. Altro valore che è andato a peggiorare è la metrica WeightedMethods che passa da 32 a 50, che si traduce in una maggiore difficoltà e sforzonel riutilizzo e nella manutenzione delle classi. Inoltre, con queste tecniche, il va-lore del RFC2, ovvero Response For Class che indica il volume di interazioni trale classi, è aumentato con conseguente aumento sia della complessità del progettoe sia dell’attività di Testing.

2Misurato tramite Stan4J, un ulteriore tool disponibile come estensione per Eclipse

45

Struttura Pre-Refactoring

Struttura Post-Refactoring

3.5 Esecuzione post-RefactoringA questo punto, eseguendo nuovamente il Software, il suo comportamento nonè variato. Immettendo infatti i valori immessi inizialmente mostrati in Figura3.3notiamo come il costo finale, così come i punti fedeltà, non sono minimamentevariati.

Esecuzione Client e Server post-Refactoring

46

Conclusione

Con il presente elaborato si è voluto dare risalto ad un aspetto fondamentale delsoftware, ovvero aspetti relativi alla Qualità. Si è partiti con la definizione di Qua-lità, secondo la norma ISO-IEC 9126, per poi passare all’analisi delle tecniche dipulizia e organizzazione del codice, definite anche come Attività di Refactoring,ed infine si è passati ad attuare tali tecniche su un semplicissimo programma.Con l’esempio mostrato, infatti, si è voluto dimostrare come, con l’utilizzo disemplici tecniche, si sia arrivati ad un codice molto più snello e comprensibile,non più formato da lunghi metodi con tante responsabilità. Tali interventi hannopermesso, inoltre, di rende il codice facilmente modificabile, così da rendere lafase di Manutenzione, o volendo anche un’intera fase di Reingegnerizzazione delsoftware, un intervento molto più semplice e rapido. Tuttavia è bene notare chequesta attività, rapportando ai valori relativi alle metriche di qualità che sono sta-ti migliorati, ha anche degli svantaggi : ridurre il numero di righe di codice permetodo tende ad aumentare il numero di chiamate a sottoprogramma, così comel’attuazione del polimorfismo, seppur sia una tecnica ottima nell’ambito della pro-grammazione Object Oriented, riduce la complessità ciclomatica a livello staticoma durante l’esecuzione il linkaggio al corpo giusto del metodo virtuale è affidatoal linker, che interrogherà a sua volta la Tabella dei Metodi Virtuali per trovarela giusta corrispondenza tra firma e corpo del metodo. In definitiva, da un lato ilRefactoring migliora sensibilimente la qualità del codice sorgente, ma dall’altroè bene notare come non si debba esagerare con questa attività. Un uso impropriodi tale tecniche potrebbe comportare danneggiamenti alle funzionalità, nonchè undegrado generale del sistema dovuto ad un intreccio di metodi. Prima di iniziaretale attività, è bene comporre una lista di tutto ciò che si vuole migliorare, cosìda poter organizzare preventivamente nel miglior modo possibile i cambiamentiche il software dovrà subire, e affiancando questa fase ad un attenta fase di test.L’obiettivo principale del Refactoring, ricordiamo, è Migliorare la struttura in-terna del software senza modificare e pregiudicare il suo comportamento esternoed è quindi quasi un dovere attuare al meglio qualsiasi tipo di tecnica senza peròstravolgere l’esperienza utente.

47

Bibliografia

[1] Martin Fowler,Refactoring: Improving the Design of Existing Co-de,Addison Wesley Longman INC div Pearson Suite 300 ,1999

[2] N.Fenton, J. Bieman,Software Metrics, A Rigorous and PracticalApproach, 2015

[3] Wikipedia.https://it.wikipedia.org

[4] IEEE Standard Glossary of Software Engineering.http://www.mit.jyu.fi/ope/kurssit/TIES462/Materiaalit/IEEE_SoftwareEngGlossary.pdf

[5] Ian Sommerville,Software Engineering, Tenth Edition, Pearson, 2016

[6] Documentazione Eclipse.http://help.eclipse.org/neon/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2Fint_eclipse.htm

[7] Documentazione Visual Studio.https://code.visualstudio.com/Docshttps://msdn.microsoft.com/it-it/library/719exd8s.aspx

[8] Bad Smells Code.https://sourcemaking.com/refactoring/smells

[9] Kerievsky Joshua, Refactoring To Patterns, Industrial Logic

[10] R. Sbavaglia, Le metriche ed il loro utilizzo nello sviluppo del Softwarehttp://torlone.dia.uniroma3.it/sistelab/annipassati/sbavaglia.pdf

48