Skip to content
Snippets Groups Projects
Commit 99e0de45 authored by Giovanni Colombo's avatar Giovanni Colombo
Browse files

Merge branch 'FixLezione7' into 'master'

Lezione 7: Typos

See merge request silab-gang/sweng!83
parents c14412d9 88a0b582
No related branches found
No related tags found
No related merge requests found
# Progettazione
Durante le lezioni, per discutere di progettazione siamo partiti da un esempio di programma in C che stampa una canzone.
Il codice considerato è completamente illegibile:
Il codice considerato è completamente illeggibile:
```c
#include <stdio.h>
......
......@@ -13,4 +13,4 @@ Spesso le motivazioni dietro un refactoring sono:
- precedente __design molto complesso e poco leggibile__, a causa della velocità del passare ad uno _scenario verde_;
- __preparare il design di una funzionalità__ che non si integra bene in quello esistente; dopo aver raggiunto uno _scenario verde_ in una feature, è possibile che la feature successiva sia difficile da integrare.
In questo caso, se il _refactoring_ non è banale è bene fermarsi, tornare indietro e evolvere il codice per facilitare l'iterazione successiva (__design for change__).
- presenza di __debito tecnico__ su lavoro fatto in precendenza, ovvero debolezze e "scorciatoie" che ostacolano notevolmente evoluzioni future: _"ogni debito tecnico lo si ripaga con gli interessi"_.
- presenza di __debito tecnico__ su lavoro fatto in precedenza, ovvero debolezze e "scorciatoie" che ostacolano notevolmente evoluzioni future: _"ogni debito tecnico lo si ripaga con gli interessi"_.
......@@ -21,7 +21,7 @@ Così facendo, le classi rimangono semplici e si agevola la riusabilità.
le classi devono essere aperte ai cambiamenti (_opened_) ma senza modificare le parti già consegnate e in produzione (_closed_).
Il refactoring è comunque possibile, ma deve essere preferibile estendere la classe attuale.
3. __<span style="color: darkgreen"><big>L</big></span>ISKOV SUBSTITUTION PRINCIPLE__:
c'è la garanzia che le caratteristiche eredidate dalla classe padre continuinino ad esistere nelle classi figlie.
c'è la garanzia che le caratteristiche ereditate dalla classe padre continuino ad esistere nelle classi figlie.
Questo concetto si collega all'aspetto __contract-based__ del metodo Agile: le _precondizioni_ di un metodo di una classe figlia devono essere ugualmente o meno restrittive del metodo della classe padre.
Al contrario, le _postcondizioni_ di un metodo della classe figlia non possono garantire più di quello che garantiva il metodo nella classe padre.
Fare _casting_ bypassa queste regole.
......@@ -140,7 +140,7 @@ Di seguito ne sono elencati alcuni:
- __codice duplicato__: si può fare per arrivare velocemente al verde quando si usa la tecnica TDD, ma è da rimuovere con il refactoring. Rischia di portarsi dietro degli errori o particolarità legate al applicazione originale di questo codice. È dunque importante cercare di fattorizzare il più possibile.
- __metodi troppo lunghi__: non è un vincolo "_hard_" dato che dipende dai casi ma solitamente sono poco leggibili e poco riusabili;
- __troppi livelli di indentazione__: scarsa leggibilità e riusabilità, è bene fattorizzare il codice invece che avere una serie di if e for _innestati_ che lo rendono confusionario, quindi è meglio creare dei metodi con nomi chiari per evitare ciò.
- __troppi attributi__: suggerisce che la classe non rispetta la single responsability, ovvero fa troppe cose;
- __troppi attributi__: suggerisce che la classe non rispetta la single responsibility, ovvero fa troppe cose;
- __lunghe sequenze di _if-else_ o _switch___: possono essere sostituiti da strutture basate su polimorfismo e collegamento dinamico;
- __classe troppo grande__;
- __lista parametri troppo lunga__: se proprio ne ho bisogno meglio raggrupparli in una struttura e passarli come unico parametro;
......@@ -150,10 +150,10 @@ Di seguito ne sono elencati alcuni:
- __codice morto__: nel programma non deve essere presente del codice irraggiungibile, commentato o non testato.
Questo appesantisce il progetto o porta a possibili rischi, è quindi preferibile eliminarlo.
Nel caso in cui dovesse tornare utile è possibile recuperarlo utilizzando strumenti di versioning, accedendo a commit precedenti alla sua cancellazione.
- __getter e setter__: Questi metodi causano la perdita dell'incapsulation e dell'information hiding, perchè esportano esternamente il segreto contenuto nella classe.
- __getter e setter__: Questi metodi causano la perdita dell'encapsulation e dell'information hiding, perchè esportano esternamente il segreto contenuto nella classe.
Sono utili nella fase preliminare della stesura del codice, è importante rimuoverli per far spazio a dei metodi che permettano all'utente di eseguire una specifica operazione da lui richiesta, piuttosto che fornirgli il dato e permettergli di elaborarlo come meglio crede (vedi principio di [__tell don't ask__](./04_tell-dont-ask.md) nella prossima sezione).
Ecco alucni link utili per approfondire i code smell:
Ecco alcuni link utili per approfondire i code smell:
- [Refactoring guru](https://refactoring.guru/refactoring/smells)
- [Wikipedia](https://en.wikipedia.org/wiki/Code_smell)
- [Luzkan](https://luzkan.github.io/smells/)
# Esempio con gerarchia Card / Deck
In questo esempio sono trattati numerosi principi, come l'_interface segreagation_, _linking dinamico/statico_, _implementazione di interfacce multiple_ e il _contract based design_ vs la _programmazione difensiva_.
In questo esempio sono trattati numerosi principi, come l'_interface segregation_, _linking dinamico/statico_, _implementazione di interfacce multiple_ e il _contract based design_ vs la _programmazione difensiva_.
- [**Interface segregation**](./01_interface-segregation.md)
- [**Collegamento statico e dinamico**](./02_collegamento-statico-dinamico.md)
......
# Interfacce multiple
Tornando all'esempio, la classe `Deck` (che implementa `CardSource`) __può implementare anche altre interfacce__, come `Shuffable` o `Iterable<Card>`.
Al metodo precedente interessa solo che Deck abbia le capacità specificate in `CardSource`, se poi implementa anche altre interfaccie è ininfluente.
Al metodo precedente interessa solo che Deck abbia le capacità specificate in `CardSource`, se poi implementa anche altre interfacce è ininfluente.
```plantuml
@startuml
......
......@@ -44,7 +44,7 @@ Esempio: _library_, _week_ (una settimana ha 7 giorni).
Esempio: _name of the member_ (se ci fosse stato).
Al termine di questa fase, si avrà una lista di classi _"certe"_ e _"incerte"_.
In questo esempio, sono soppravvisuti i termini _journal_, _book_, _copy_ (of _book_), _library member_ e _member of staff_.
In questo esempio, sono sopravvissuti i termini _journal_, _book_, _copy_ (of _book_), _library member_ e _member of staff_.
### Relazioni tra classi
......@@ -143,6 +143,6 @@ hide empty methods
@enduml
```
È imporante però preoccuparsi delle __cardinalità__ delle relazioni: è sì vero che un `BorrowableItem` può non _essere una copia di_ un `Book` e di un `Journal`, ma deve essere copia di _esattamente_ una delle due opzioni.
UML prevede un __linguaggio OCL__ ([Object Constraint Language](https://en.wikipedia.org/wiki/Object_Constraint_Language)) per esprimere vincoli divesamente impossibili da esprimere in un diagramma.
È importante però preoccuparsi delle __cardinalità__ delle relazioni: è sì vero che un `BorrowableItem` può non _essere una copia di_ un `Book` e di un `Journal`, ma deve essere copia di _esattamente_ una delle due opzioni.
UML prevede un __linguaggio OCL__ ([Object Constraint Language](https://en.wikipedia.org/wiki/Object_Constraint_Language)) per esprimere vincoli diversamente impossibili da esprimere in un diagramma.
È anche possibile scrivere il _constraint_ in linguaggio naturale come __nota__.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment