# Progettazione
## SOLID
In ambito di progettazione software é utile tenere in mente i principi SOLID:
### Single-responsability principle
Ogni elemento di un software, che sia una classe, una funzione o una variabile deve avere al suo interno una sola responsabilitá.
### Open–closed principle
Un modulo dovrebbe essere aperto per le estensioni, ma chiuso per le modifiche. Vogliamo cioé essere capaci di cambiare il comportamento delle classi senza cambiarne il codice sorgente (se non modifico, non faccio errori).
### Liskov substitution principle
Gli oggetti della sottoclasse devono rispettare il contratto (ossia la specifica) della superclasse permettendo quindi che una qualsiasi classe di un certo tipo puó essere sostituita da un qualsiasi classe del sottotipo senza “accorgersi" della differenza.
Regole da seguire per permetterlo:
- regola della segnatura: un sottotipo deve avere tutti i metodi del sopratipo e le segnature dei metodi del sottotipo devono essere compatibili
- regola dei metodi: i metodi in overriding devono avere lo stesso comportamento/scopo dei metodi del supertipo
- regola della proprietá: il sottotipo deve rispettare l'invariante del supertipo.
### Interface segregation principle
Sarebbero preferibili più interfacce specifiche, che una singola generica.
### Dependency inversion principle
Dipendere dalle astrazioni, non dagli elementi concreti cioé invertire la pratica tradizionale secondo cui i moduli di alto livello nelle gerachia di ereditarietà dipendono da quelli di basso livello. **Quindi dipendere da interfacce e classi astratte, non da metodi e classi concrete**. Ogni classe C che si ritiene possa essere estesa in futuro, dovrebbe essere definite come sottotipo di un'interfaccia o di una classe astratta A – Tutte le volte che non è strettamente indispensabile riferirsi ad oggetti della classe concreta C, è meglio riferirsi invece a oggetti il cui tipo statico è la classe astratta A, non C – In questo modo, sarà più facile in seguito modificare il codice client per utilizzare invece di C altre classi concrete sottotipi di A.
## Aspetti strutturali del software
La “correttezza funzionale” di un progetto è fondamentale ma possiamo anche valutarlo rispetto a requisiti strutturali:
- Accoppiamento
- Coesione
- Principio open-closed
### Accoppiamento
Un alto grado di accoppiamento significa alta interdipendenza tra le classi e quindi difficoltà di modifica e manutenzione. Un basso accoppiamento è requisito fondamentale per creare un sistema comprensibile e modificabile nel tempo.
Le forme da evitare si hanno quando un metodo manipola direttamente le variabili di stato di altre classi e scambia informazioni attraverso variabili temporanee. Per ridurre l’accoppiamento i metodi dovrebbero passare la minor quantità di informazione possibile attraverso il minor numero di parametri.
### Cohesion
Solo gli elementi fortemente correlati dovrebbero stare nello stesso modulo. Il modulo rappresenterebbe una chiara astrazione e sarebbe più semplice da capire. Alta coesione solitamente porta a basso accoppiamento.
Tre tipi di coesione:
- method
- class
- inheritance
## Metriche di un software
E’ possibile definire delle misure (dette metriche) di queste caratteristiche:
- Weighted Methods per Class (WMC): Numero dei metodi pesati per la loro complessità. In genere la maggior parte delle classi dovrebbe avere un numero limitato di metodi, essere semplici e fornire astrazioni e operazioni specifiche.
- Depth of Inheritance Tree (DIT): In genere le classi sono solitamente “vicine” alla radice e si tende a non sfruttare al pieno l'ereditarietá (favorendo comprensibilità rispetto a riusabilità).
- Number of Children (NOC)
- Coupling Between Classes (CBC): si tende a scrivere classi auto-contenute, cioé poco accoppiate
- Response for a Class (RFC): Il numero totale di metodi che possono essere invocati da un oggetto della classe.
- Lack of Cohesion in Methods (LCOM): cattura la “vicinanza” tra i metodi di una classe, cioé misura quanto accedono a variabili/attributi comuni.
## Software malfatto:
- Rigido: la tendenza del software ad essere difficile da cambiare, anche in modo semplice (quando c'é un alto livello di accoppiamento).
- Fragile: la tendenza del software a “rompersi” in molti punti ogni volta che viene cambiato un aspetto.
- Immobile: l’incapacità di riusare software da altri progetti o da altre parti dello stesso progetto
- Viscoso: quando l’uso di anti-pattern, scorciatoie e metodologie notoriamente errate è più facile dell’uso dei metodi che rispettano il progetto. Cioé se scrivi un softwate in cui é piú facile fare la cosa sbagliata e difficile fare quella giusta allora hai scritto un software troppo viscoso.
Consigli pratici per software di qualitá:
- Minimizzazione dell’interfaccia: se non serve che sia pubblico sempre privato. Tutti i getter che vuoi (anche se di solito é assurdo avere tanti getter), ma meno setter possibili.
- Pochi parametri nei metodi: meno parametri possibili. Particolarmente pericolose sono parametri di fila dello stesso tipo .. Un’inversione non genera errori di compilazione ma provoca malfunzionamenti difficilmente diagnosticabili.
- Metodi di piccole dimensioni
- Spostare i metodi nella classe in cui sono definiti i dati che usano.
- Sostituire l'uso dello Switch con ereditarietà, enum, pattern (State).
- Non usare gli Anti-Pattern!: classe BLOB che contiene tutto, codice duplicato, metodi lunghi (se il codice di un metodo diventa troppo lungo per poterlo capire facilmente, bisogna estrarne delle parti come metodi di servizio).
- Usare poco eccezioni non é una buona cosa
## Refactoring
Refactoring é cosa buona e giusta: È abbastanza difficile fare la cosa giusta al primo colpo. Ovvero il miglioramento del progetto del codice esistente senza cambiarne il comportamento.
## Commentare
Nei linguaggi OO è generalmente una buona idea fornire un commento all’inizio di ogni metodo, che dettagli il significato del metodo, eventuali vincoli, requisiti ecc .
Se si può rendere il codice abbastanza chiaro da poterlo considerare autocommentato, questo è ciò che va fatto .. occorre commentare solo quando è necessario dire qualcosa con maggiore chiarezza di quanto non possa fare il codice.
### Convenzioni di programmazione
- Nomi di classi e interfacce hanno l’iniziale maiuscola:
- Nomi di variabili e metodi (in Java, c# no ad esempio) iniziano sempre con una minuscola.
- I nomi delle costanti sono completamente maiuscoli.
- Se il nome è composto da più parole, ciascuna di queste è scritta con l’iniziale maiuscola