2. Agenda
• Codice adattivo
• Dipendenze
• Interfacce e modelli di programmazione
• Test unitari
• Refactoring
• SOLID
• Cos’è SOLID
• Singola responsabilità
• Aperto / Chiuso
• Sostituzione Liskov
• Segregazione di interfaccia
• Inversione di dipendenza
15/09/2018 2
3. Dipendenze
Una dipendenza è una relazione tra due entità distinte
per cui non è possibile eseguire alcuna funzione o
esistere senza l'altra.
Le dipendenze sono necessarie, ma devono anche essere
gestite con cura per evitare problemi problemi in fase di
sviluppo.
Sample_01.cs
Code smells: un modo per dire che alcuni codici sono
potenzialmente problematici.
15/09/2018 3
4. Dipendenze
AccountController dipende sempre dalle implementazioni
SecurityService e User Repository.
Qualunque dipendenza che SecurityService e
UserRepository hanno sono ora dipendenze implicite di
AccountController.
L'AccountController è ora estremamente difficile da
testare: le due classi sono impossibili da «mokkare» con i
metodi convenzionali.
Il metodo SecurityService.ChangeUsersPassword richiede
ai client di caricare oggetti User.
15/09/2018 4
5. Dipendenze
Un'interfaccia in C# è una definizione di tipo simile a una
classe, tranne per il fatto che rappresenta puramente un
contratto tra un oggetto e il suo utilizzatore.
Sample_02.cs
Iniezione di dipendenza (Dependency injection*): è una
tecnica in base alla quale un oggetto (o metodo statico)
fornisce le dipendenze di un altro oggetto.
*argomento trattato nella sessione di Andrea Dottor
15/09/2018 5
6. Interfacce e modelli di programmazione
Polimorfismo: fornisce un'interfaccia singola a entità di
tipo diverso o l'uso di un singolo simbolo per
rappresentare più tipi diversi
15/09/2018 6
7. Interfacce e modelli di programmazione
Modello di progettazione del software (Software design
pattern): è una soluzione generale e riutilizzabile per un
problema che si verifica comunemente in un dato
contesto nella progettazione del software.
Possono essere abusati e non sono sempre applicabili, a
volte complicano troppo una soluzione altrimenti semplice
con un'esplosione di classi, interfacce, indirezione e
astrazione.
I modelli di progettazione tendono ad essere
sottoutilizzati o sovrautilizzati, l'equilibrio è nel trovare i
posti giusti per applicare i modelli giusti.
15/09/2018 7
8. Interfacce e modelli di programmazione
Il modello Null Object (Null Object pattern) consente di
evitare di lanciare accidentalmente una Null
ReferenceException e una pletora di codice di controllo
degli oggetti nulli
15/09/2018 8
Sample_03.cs
9. Interfacce e modelli di programmazione
Il modello Adattatore d’oggetto (Object Adapter pattern)
consente di utilizzare l'interfaccia di una classe esistente
come un'altra interfaccia.
15/09/2018 9
Sample_04.cs
10. Interfacce e modelli di programmazione
Il modello di strategia (Strategy pattern) consente di
modificare il comportamento desiderato di una classe
senza richiedere la ricompilazione, potenzialmente anche
durante l'esecuzione stessa.
15/09/2018 10
Sample_05.cs
11. Interfacce e modelli di programmazione
Si dice che un'interfaccia sia fluente (fluent) se restituisce
se stessa da uno o più dei suoi metodi
15/09/2018 11
Sample_06.cs
12. Test unitari
I test unitari sono la scrittura di codice che testa altro codice.
Ogni volta che viene eseguito un test unitario, viene segnalato
il successo o il fallimento del test con un semplice indicatore
visivo vero o falso, spesso verde o rosso.
Se tutti i test unitari passano, il codice di produzione da loro
testato è considerato funzionante. Se anche un singolo test su
migliaia ha esito negativo il codice di produzione nel suo
insieme viene considerato come non funzionante.
TDD (Test-driven development) -> Red, green, refactor! ☺
15/09/2018 12
13. Refactoring
Il refactoring è il processo di miglioramento della
progettazione del codice esistente, dopo che è già stato
scritto.
Ogni refactoring è diverso per dimensione e ambito.
Un refactoring potrebbe essere un piccolo cambiamento
ad un nome di variabile per facilitare la chiarezza, o
potrebbe essere un cambiamento architettonico più
radicale come dividere la logica dell'interfaccia utente
dalla logica di dominio quando i due sono diventati
inopportunamente intimo
15/09/2018 13
14. Cos’è SOLID ?
15/09/2018 14
What is SOLID?
S
SRP
Single
Responsibility
Principle
O
OCP
Open/Closed
Principle
L
LSP
Liskovs
Substitution
Principle
I
ISP
Interface
Segregation
Principle
D
DIP
Dependency
Inversion
Principle
SOLID è l'acronimo di una serie di procedure che, una volta
implementate insieme, rendono il codice adattabile alla
modifica. Le pratiche SOLID sono state introdotte da Robert
Cecil Martin (Uncle Bob) ad inizio 2000
15. Principio di singola responsabilità
Ogni oggetto si deve focalizzare su una singola
responsabilità e deve avere quindi un solo motivo per
cambiare. In altre parole, ogni oggetto deve eseguire una
cosa sola.
Oggetti piccoli e concisi
Testabilità
Leggibilità
Manutenzione più semplice
15/09/2018 15
Sample_07.cs
16. Principio aperto / chiuso
Le classi dovrebbero essere aperte per l’estensione e
chiuse per la modifica.
Si dovrebbe essere in grado di aggiungere nuove
funzionalità e di estendere una classe senza cambiare il
suo comportamento interno.
L’obiettivo principale di questo principio è quello di evitare
di introdurre bug ed errori in genere alle funzionalità
esistenti a seguito dell’aggiunta di altre funzionalità nella
classe.
15/09/2018 16
Sample_08.cs
17. Principio di sostituzione di Liskov
Il principio di sostituzione di Liskov (LSP) afferma che si
dovrebbe essere sempre in grado di utilizzare qualsiasi
classe derivata al posto di una classe genitore (classe
base) senza apportare alcuna modifica.
Il principio garantisce che una classe derivata non
influenzi il comportamento della classe padre.
Il principio prende il nome da Barbara Liskov, che per
prima ha descritto il problema nel 1988.
15/09/2018 17
Sample_09.cs
18. Principio di segregazione delle interfacce
Una classe client non dovrebbe dipendere da metodi che
non usa, e che pertanto è preferibile che le interfacce
siano molte, specifiche e piccole (composte da pochi
metodi) piuttosto che poche, generali e grandi.
Questo consente a ciascun client di dipendere da un
insieme minimo di metodi, ovvero quelli appartenenti alle
interfacce che effettivamente usa.
Ogni interfaccia rappresenta il singolo ruolo che una
classe può avere nei diversi contesti o diverse interazioni
con altri oggetti.
15/09/2018 18
Sample_10.cs
19. Principio di inversione delle dipendenze*
l principio di inversione delle dipendenze aiuta a
disaccoppiare il codice in modo tale che le classi
dipendano da astrazioni piuttosto che da implementazioni
concrete.
Una caratteristica fondamentale è la programmazione per
astrazioni: il “consumo” di classi avviene mediate l’uso
di astrazioni (Interfacce e classi astratte), piuttosto che a
livello di specifiche implementazioni
*argomento trattato nella sessione di Andrea Dottor
15/09/2018 19
Sample_11.cs
21. Metriche - Visual Studio
Indice di manutenibilità
Se il punteggio è compreso tra 0 e 9 -> S.O.L.I.D violation
Complessità ciclomatica
Se il punteggio è maggiore di 30 a livello di membro o più
di 80 a livello di tipo ->OCP violation or SRP violation
Profondità dell'ereditarietà
Se il punteggio è superiore a 25 -> OCP violation, LSP
violation, ISP violation, or DIP violation
Accoppiamento
Se il punteggio è superiore a 4 -> OCP violation, LSP
violation
Righe di codice
Se il codice ha più di 20 lines -> SRP violation
15/09/2018 21