Esempio di trascrizione di una lezione
Il testo integrale di una lezione universitaria di ingegneria del software, così come esce da Scriba.
Questo è il testo integrale, parola per parola come lo ha prodotto Scriba — refusi compresi, se ce ne sono. La trascrizione automatica sbaglia su nomi propri e sigle, e vedere quanto sbaglia su una lezione vera vale più di qualunque percentuale dichiarata.
Nota: il file scaricabile è un testo continuo, senza a capo. Qui è spezzato in paragrafi solo per poterlo leggere a schermo.
Oggi parliamo di alcuni degli argomenti più importanti nell'analisi e progettazione del software, i pattern di progettazione e i code smell, che sono i due lati della stessa medaglia. I primi riguardano come progettare bene e i secondi come accorgersi di aver progettato male. Partiamo dalla definizione di design pattern. Che cos'è? È una soluzione comune a un problema di progettazione ricorrente.
Questi differiscono da un altro tipo di pattern, che si chiamano pattern GRASP, con cui condividono parte del nome, ma questi ultimi sono principi, consigli. mentre i design pattern si spingono oltre e arrivano fino allo schema delle classi partiamo dalla classificazione GOF prima di tutto per cosa sta GOF? sta per Gang of Four che deriva dal fatto che i suoi ideatori erano quattro persone si tratta di 23 pattern in totale Però nel corso ne vedremo solamente sette. Come si classificano? Si classificano su due assi, per lo scopo e per il raggio d'azione. per quanto riguarda lo scopo possono essere creazionali, strutturali o comportamentali per quanto riguarda il raggio d'azione possono essere su classi oppure su oggetti facciamo qualche esempio di combinazioni di questi due assi abbiamo per esempio il factory method che è un creazionale su classi abbiamo per esempio l'adapter che è un pattern strutturale e abbiamo observer e strategy che sono due pattern comportamentali su oggetti adesso soffermiamoci su questi ultimi due perché spesso all'inizio vengono confusi Allora, partiamo dal definire questi due pattern, indicando quale problema risolvono e come lo risolvono. Lo strategy risponde al problema di un insieme di algoritmi correlati e variabili e vogliamo poterli cambiare. Cambiare come? Scegliere a quale utilizzare.
Quindi come risolviamo questo problema? Ogni algoritmo viene messo in una classe separata, tutte con un'interfaccia comune. Il context tiene un riferimento alla strategia e la usa senza sapere quale sia, Mentre il client può sostituirla a runtime con una strategia diversa della stessa interfaccia per sostituirla con una strategia diversa all'occorrenza. Per quanto riguarda l'observer, il problema che si pone è quello di più oggetti che vogliono sapere quando un altro oggetto cambia stato. Ognuno reagendo a modo proprio.
Il publisher non deve conoscerli. Prima di tutto vediamo chi è il publisher nel pattern observer. È l'oggetto che viene osservato dagli altri. Come risolviamo questo problema? Abbiamo un'interfaccia, che è il subscriber, e ogni subscriber si registra al publisher in modo che possa essere avvisato quando succede qualcosa.
Quindi qual è la distinzione tra questi due pattern? Lo strategy serve a scambiare un comportamento, quindi scegliere quale comportamento vogliamo applicare. Observer serve a notificare un cambiamento a più interessati. Cos'hanno in comune? Si basano entrambi su polymorphism. e forniscono delle protected variations vediamo anche un'altra coppia di pattern che vengono spesso confusi che sono l'adapter e il facade partiamo vedendo l'adapter abbiamo due interfacce incompatibili che però hanno bisogno di parlarsi Quindi cosa facciamo per permettere che comunichino tra loro? Mettiamo in mezzo un oggetto adattatore che converte i messaggi che si devono scambiare. Esistono in due forme, adapter di classe e adapter di oggetto.
Invece la facade si applica quando abbiamo un sottosistema disordinato e complicato. Mettiamo davanti a questo sottosistema un punto di contatto unico che offre un'interfaccia semplificata in modo che chi deve interfacciarsi con questo sottosistema non debba sapere di tutto e di più oppure confondersi su cosa effettivamente deve chiamare. La distinzione tra questi due pattern è che l'adapter converte un'interfaccia che c'è già, mentre facade semplifica l'accesso a un insieme di cose. Vediamo che cosa risolvono.
L'adapter risolve un'incompatibilità, mentre facade risolve una complessità. Al facade di solito si accede tramite un singleton e sostiene il low coupling aggiungendo un livello di indirection Vediamo a questo punto che cos'è singleton e anche i suoi difetti Prima di tutto cos'è? è una sola istanza di una classe con un punto di accesso globale cioè tutti gli oggetti che si interfacciano con essa si interfacciano sempre con la stessa istanza abbiamo un metodo statico getInstance che ci restituisce l'istanza unica che è stata creata e ha un costruttore privato per negare la possibilità di crearne una ulteriore quando ne esiste già una. Come si riconosce in UML? Abbiamo solitamente un 1 in alto a destra nella classe. Le due implementazioni possono essere lesi oppure non lesi.
Come si differenziano? Quelle lazy vengono create solo quando servono, perciò se magari all'avvio del nostro software quel singleton non è necessario ma invece ne abbiamo bisogno solamente nel momento in cui una richiesta o una certa azione appunto richiede di usare questa istanza, la creiamo solo in quel momento. invece possiamo avere quelle non lazy che vengono create subito anche se non sono necessarie in quel momento quali sono i limiti? serve synchronized su getinstance oppure con più thread rischiamo di avere due o più istanze non funziona bene nelle applicazioni distribuite perché comunque ogni macchina virtuale avrebbe la propria istanza e quindi questi sono due grossi limiti che si applicano in situazioni particolari ma non proprio di nicchia vediamo invece adesso i code smell allora che cosa sono i code smell? sono delle caratteristiche del codice che possono essere indizio di una cattiva pratica Non si tratta necessariamente di bug, è proprio un cattivo odore, cioè qualcosa che non va ma che non è effettivamente un bug o un problema di per sé. Che cosa si fa? Si fa refactoring per toglierli. In cosa consiste il refactoring? Consiste nel riscrivere il codice senza cambiarne il comportamento esterno a piccoli passi rieseguendo i test dopo ognuno. Quindi una cosa importantissima da tenere sempre a mente è che il refactoring non corregge i bug. vediamo adesso le 5 famiglie di code smell abbiamo i bloaters che sono codice sproporzionato ad esempio long method, large class, long parameter list poi abbiamo gli object orientation abusers che è l'uso sbagliato dell'object oriented che sono lo switch statement e il refused bequest abbiamo poi i change preventers che sono parti troppo accoppiate che impediscono le modifiche per esempio shotgun surgery poi abbiamo i dispensables, cose che è meglio togliere duplicated code, data class, comments infine abbiamo i couplers che sono accoppiamento eccessivo come ad esempio il code smell, feature envy Per ognuno di questi il sintomo si può riassumere in una sola frase.
Per esempio il long method è un metodo con troppe righe e quindi è probabilmente una buona idea dividerlo in più metodi separati che fanno una parte dell'esecuzione che sia, come dire, che abbia un senso proprio. Poi, come possiamo definire refused bequest? La sottoclasse non usa quello che eredita e quindi la gerarchia è sbagliata. Poi abbiamo shotgun surgery. Per una modifica piccola devi toccare tante classi diverse che crea grossi problemi perché comunque modificando tante classi si rischia di rompere qualcosa o di cambiare comportamenti e di non rendersene conto subito perché passano inosservati.
Le data class, semplicemente sono classi che sono solo contenitori di dati ma che non hanno logica e quindi non fanno niente Infine vediamo per esempio il feature envy, che cos'è? È un metodo che usa più i dati di un altro oggetto che i propri Vediamo delle coppie sintomo rimedio switch statement se puoi sfruttare il polimorfismo replace conditional with polymorphism è il metodo di refactoring adatto a risolvere questo problema per quanto riguarda il feature envy se il metodo sta chiaramente nel posto sbagliato applichiamo il metodo di refactoring move method che consiste semplicemente nel spostare il metodo nella classe più corretta per quanto riguarda il long method il metodo di refactoring che possiamo applicare è extract method se il problema sono le variabili locali invece replace temp with query oppure introduce parameter object che sono tutti dei metodi di refactoring che si basano appunto su motivi diversi per cui il metodo sia lungo. Quindi, riassumendo, la regola del 3. Si fa refactoring quando la stessa porzione è riusata almeno tre volte. Il copia e incolla è permesso una volta sola.
Gli altri momenti buoni, quando si aggiunge una funzionalità, quando si corregge un bug e durante una revisione del codice. Si può fare refactoring anche in questi momenti. Quindi, i pattern ci dicono come fare le cose bene, mentre i code smell come accorgerci di non averle fatte bene. Questo chiude questa piccola lezione sui design pattern e i code smell.
Scarica il file originale — è lo stesso che riceveresti tu.
Tutto il materiale di questa sezione viene da una sola lezione vera. Gli altri formati · quanto sarebbe costata.