From f056c82cd5448e850608d12fabfc17c891a3b425 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Sat, 20 Jan 2024 11:20:32 +0100 Subject: [PATCH 01/23] chore: aggiunta TOC --- docs/it/refactoring.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/it/refactoring.md diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md new file mode 100644 index 00000000..14b65d8d --- /dev/null +++ b/docs/it/refactoring.md @@ -0,0 +1,8 @@ +# Table Of Contents + +- Cos'è il refactoring? +- Quando fare refactoring? +- Quando NON fare refactoring? + +# Altre idee +- Differenza (Di intenti oltre che di tempo ed effort) tra refactoring automatico e manuale \ No newline at end of file From cb96cb11414bfe7e0377d9d2ca205811344ab9db Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Sat, 20 Jan 2024 11:20:57 +0100 Subject: [PATCH 02/23] chore: aggiunta TOC --- docs/it/refactoring.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 14b65d8d..26b8a45b 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -5,4 +5,5 @@ - Quando NON fare refactoring? # Altre idee -- Differenza (Di intenti oltre che di tempo ed effort) tra refactoring automatico e manuale \ No newline at end of file + +- Differenza (Di intenti oltre che di tempo ed effort) tra refactoring automatico e manuale From 467d20ceb450b52f8076f8768e6803da43c9a87b Mon Sep 17 00:00:00 2001 From: Mario Ravalli Date: Sat, 17 Feb 2024 15:39:47 +0100 Subject: [PATCH 03/23] feat: Aggiunta primi contenuti capitolo refactoring (#208) Co-authored-by: Michael Di Prisco --- docs/it/refactoring.md | 135 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 26b8a45b..eb078b87 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -7,3 +7,138 @@ # Altre idee - Differenza (Di intenti oltre che di tempo ed effort) tra refactoring automatico e manuale + +## Che cos'è il refactoring + +Alcuni direbbero che il refactoring è l'arte di crearsi problemi. +Il refactoring è un insieme di attività dedite a rivedere una o più parti del codice con cui è composta la nostra applicazione. +Può interessare un singolo metodo, una singola classe, un intero modulo. +L'obiettivo di queste attività è rivedere la logica piuttosto che la scrittura del codice che la compone, in modo da ottenere migliori performance (o un maggior disaccoppiamento, una maggiore testabilità) senza però, in alcun modo, alterarne il comportamento e, soprattutto, aggiungere nuove funzionalità. +Se l'attività è stata fatta bene, al termine avremo un codice più pulito, comprensibile, di cui non è stato alterato il comportamento e che passa perfettamente tutti i test già presenti. +Ma andiamo per gradi. + +## Benefici + +Uno dei principali benefici che otterremo con il refactoring è la rimozione di porzioni di codice non performanti, sostituiti da codice più trasparente e chiaro. E con questo, un'evidente riduzione del debito tecnico accumulato. +Un codice scritto bene, non solo aiuta a chi lo ha scritto di poterlo rivedere a distanza di qualche tempo senza troppi mal di testa ma, con il crescere del software e l'introduzione di nuove funzionalità, rende più semplice la vita ai futuri sviluppatori che dovranno interfacciarsi con esso. +Da un codice scritto bene, si possono ottenere migliori performance. Magari non direttamente ma, una buona attività di refactoring ci permetterà di avere molto più chiaro come il software interagisce, dandoci la possibilità di individuare eventuali colli di bottiglia, anche a livello architetturale. + +## Quando + +La scrittura del codice non è del tutto lineare, soprattutto se scritto a più mani. Ogni sviluppatore ha un suo stile, delle sue convinzioni, un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. +Sono diverse le occasioni in cui è possibile fare refactoring e, in alcune di queste, non solo è consigliato ma obbligatorio. +Poniamo il caso che abbiamo una parte del nostro software con del codice "legacy", magari scritto rispettando dei pattern che, nel tempo, si sono rivelati sbagliati. Oppure scritto di fretta, senza rispettare i principi SOLID e con metodi e variabili che hanno nomi provvisori. +O ancora, il codice scritto risulta difficile da testare, perché presenta metodi o classi poco disaccoppiate. Con metodi privati che non fanno attività atomiche. +Fatta una rapida analisi, notiamo che, magari, ci sono dei cicli ripetuti, o parti di codice che potrebbero essere evitate se solo avessimo posto dei semafori a monte. +Con del buon refactoring potremmo rivedere il codice, eliminare delle dipendenze inutili o utilizzare dei costrutti del linguaggio più adatti, con il risultato di migliorarne la lettura, aderire agli standard del linguaggio (che, nell'ottica di rendere il nostro codice più condivisibile possibile, non fa mai male) e, perché no, migliorarne le performance e eliminare debito tecnico. +Come detto, le occasioni non mancano. +Potremmo cogliere l'occasione di una Code Review o l'aggiunta di una nuova feature. Prima di iniziarne lo sviluppo, sicuramente è buona pratica leggere il codice in cui questa nuova funzionalità andrà a integrarsi e, se quest'ultimo risulta di difficile comprensione, è un'ottima occasione per effettuarne la rifattorizzazione. Questo ci permetterebbe di ottenere una maggiore conoscienza del codice. +Un'altra, forse la migliore, dove è (quasi) obbligatorio, è la risoluzione di un bug in una parte di codice convulso, la cui sola lettura ci fa venire il mal di testa. Un'attività di refactoring potrebbe facilmente portare alla luce l'errore presente nel codice. +L'attività di refactoring può essere paragonata a una pulizia profonda di casa, piuttosto che a una routine di sistemazione della propria cameretta, necessaria per mantenere il codice sicuro, di valore ed efficiente. + +## Quando è meglio evitare + +Non sempre è utile effettuare refactoring. +Ci sono casi in cui il codice è già perfettamente ottimizzato anche se, a una vista inesperta, potrebbe risultare di difficile lettura. +Ci sono casi in cui le performance sono fondamentali e i principi SOLID non sono sempre rispettati. In questo caso, il refactoring ci porterebbe a creare dei layer aggiuntivi di codice che, sebbene ci renderebbe il codice più comprensibile, avrebbe un impatto negativo sulle performance. Un esempio sono le librerie che permettono le connessioni con delle basi di dati, dove magari è fondamentale la gestione della latenza. +In questi casi, ma più in generale, è necessario tenere a mente che l'attività di refactoring ha tra gli obiettivi quello di rivedere il codice rendendolo più mantenibile, nonché rifattorizzabile. +Diretta conseguenza di questo obiettivo, è la sua applicazione nella pratica del TDD (Test Driven Development), dove il refactoring copre uno degli step. + +## Come + +Come si può intuire, con le attività di refactoring andremo a migliorare il codice in modo da renderlo meno complesso, più mantenibile, più resiliente. +Per farlo, potremmo iniziare con: + +- Red-Green-Refactor; +- Rinominare i metodi oscuri; +- Cambiare la firma dei metodi; +- Estrarre nuovi metodi; +- Semplificare i metodi esistenti; +- Astrarre. + +### Red-Green-Refactor + +Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Driven Development), dove lo sviluppatore suddivide il processo di scrittura del codice in tre fasi: + +- Analizza quali sono le esigenze e scrive dapprima il test, che, per ovvi motivi, fallirà (_Red_); +- Scrive il codice necessario affinché il test passi (_Green_); +- Lo migliora (_Refactoring_) + +### Rinominare i metodi oscuri + +Ci sono metodi che hanno nomi degni di un codice morse ma che poco dicono sull'operazioni che vanno a intraprendere. +Un buon inizio potrebbe essere quello di rinominarli in modo che chi legge, abbia la possibilità di capire cosa fa quel metodo senza necessità alcuna di andarlo a verificare. + +### Cambiare la firma dei metodi + +Partendo dal presupposto che il codice è vivo, si ci può trovare nelle condizioni in cui al metodo inizialmente venivano passate diverse informazioni, che magari ora non sono più necessarie. E magari non lo sono perché nel frattempo, quella parte di codice era stata già snellita in qualche attività precedente. +Possiamo quindi rimuovere le informazioni in eccesso, modificandone la firma. +Inoltre, potremmo verificare, nei linguaggi tipizzati, se c'è la possibilità di rendere detta firma più stringente, ammettendo e/o restituendo tipi meno generici. + +### Estrarre nuovi metodi + +Principalmente si tratta di individuare frammenti di codice che effettuano operazioni contingentate e che possono essere estratte dal codice principale e inserite in una funzione a se stante. +Questo permette di avere un codice meno complesso da interpretare, soprattutto se la nomenclatura dei nuovi metodi è sufficientemente chiara. + +### Semplificare i metodi esistenti + +Quando il codice infrange la regola _KISS_ (Keep It Simple, Stupid). +Mentre tentiamo l'approccio dell'estrazione, ci rendiamo conto che ci sono parti di codice troppo complesse, piene di condizionalità o che generano ripercussioni su diverse parti del codice. +In questo caso, sarà necessario intervenire dapprima sul rendere meno complesso possibile il codice, rivedendo le condizionalità rendendole più semplici e chiare, magari anche rivedendo come il metodo in oggetto interagisce con il contesto circostante. + +### Astrarre + +Spesso, molte delle classi o dei metodi che vengono creati, hanno qualche parte di codice in comune, come le firme dei metodi o l'inizializzazione del contesto. +Sebbene questo potrebbe non essere sempre possibile, dopo avere estratto i metodi, ci potremmo trovare dinanzi a molti di questi che sono simili se non uguali. Con l'astrazione possiamo creare delle classi che contengono tali metodi. Metodi che potrebbero divenire ancora più semplici e generici, nonchè facili da interpretare. + +## Un Esempio + +Un caso semplice ma spesso presente nel nostro codice, potrebbe essere quello di migliorare le performance rimuovendo le variabili temporanee (il codice che segue è pseudo-codice): + +``` +function applyDiscount() { + basePrice = cart.totalPrice(); + return basePrice * discount(); +} +``` + +Il codice di partenza potrebbe già andare bene così ma, volendolo migliorare, potremmo dichiare la variabile temporanea in modo da facilitare al compilatore la vita, ovvero: + +``` +function applyDiscount() { + final basePrice = cart.totalPrice(); + return basePrice * discount(); +} +``` + +Con questa modifica, non abbiamo modificato in alcun modo il comportamento. Ovviamente, otterremo un piccolo vantaggio sulle performance a patto che, il linguaggio che stiamo usando può trarre vantaggi dalla differenza tra variabili mutabili e non. +Ma, riguardando ancora un attimo il codice, potremmo apportare un'altra modifica: + +``` +function applyDiscount() { + return cart.totalPrice() * discount(); +} +``` + +Rimuovendo la creazione di una variabile, che oggettivamente risulta solo superflua, andiamo a migliorare sicuramente le performance, non abbiamo introdotto alcuna complessità e la lettura del codice è ancora ampiamente comprensibile. + +## Costi + +Lo sviluppo di un software ha un costo, ovviamente anche il refactoring ne ha uno. Ma, fatto con regolarità, sfruttando tutte le occasioni possibili, ovvero effettuando micro-interventi di refactoring, non solo il suo costo è trascurabile ma, complessivamente, abbassa i costi grazie alla maggiore mantenibilità, scalabilità e performance ottenute. + +## Refactoring vs Riscrittura + +Si potrebbe obiettare che riscrivere una parte del nostro software, basandosi sull'esperienza acquisita, è più veloce o forse più auspicabile del refactoring. +In realtà questa affermazione è fallace: riscrivere significa affrontare un'attività che comporta del tempo non sempre definito, che apporta delle modifiche al funzionamento del software, che andrà testato probabilmente con dei nuovi test e che, non da ultimo, andrà rilasciato in blocco. +Con il refactoring, dove il dictat del non modificare in alcun modo il comportamento ci impone che i test devono continuare a funzionare senza alcun nostro intervento, è un'attività contingentata che può essere fatta durante lo sviluppo di una nuova funzionalità, se non durante la scrittura dei test stessi. E, soprattutto, il lavoro può essere rilasciato durante il normale ciclo di vita del software, annegato tra i vari rilasci e/o correzioni. + +## Automazione + +Esistono ovviamente diversi strumenti pe automatizzare le procedure di refactoring, spesso integrati direttamente nell'IDE. Forse il più famoso è Sonarqube. +Questi strumenti, basati su motori di analisi affidabili e complessi, riescono a individuare dalla banale duplicazione del codice alla mancata adozione di buone pratiche, spesso specifiche del linguaggio di programmazione adottato. +A volte riescono a fare miracoli ma, a noi preme focalizzarci su un punto della questione: l'effort. +Quanto effort occorre ad effettuare del refactoring con questi strumenti. O meglio, quanto semplificano la vita dello sviluppatore. +È innegabile che sono dei validi aiuti e che sono formidabili nel farci notare parti di codice da semplificare a cui, magari, non avevamo nemmeno fatto caso. +Ma, affidare il refactoring all'automazione, può creare delle situazioni in cui il codice modificato è così tanto da rendere complicato il controllo da parte dello sviluppatore, che sarebbe tentato di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. +C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema, darci indici ci complessità ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. +Ciò nonostante, rimangono degli ottimi aiutanti: se ad essi affidiamo la correzione di tutti quegli "errori" semplici, come la tipizzazione delle variabili (nel caso di linguaggi tipizzati, ovviamente) o la riscrittura di una funzione utilizzando il pattern _Early Return_, ci ritroveremo a dover rifattorizzare del codice già scremato, lasciando la nostra mente libera di concentrarsi sul resto del lavoro da fare. \ No newline at end of file From 3992196ce22256454e6a1d16780a2dc9e7d5339a Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Sat, 17 Feb 2024 15:41:33 +0100 Subject: [PATCH 04/23] chore: linting --- docs/it/refactoring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index eb078b87..940cb401 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -141,4 +141,4 @@ Quanto effort occorre ad effettuare del refactoring con questi strumenti. O megl È innegabile che sono dei validi aiuti e che sono formidabili nel farci notare parti di codice da semplificare a cui, magari, non avevamo nemmeno fatto caso. Ma, affidare il refactoring all'automazione, può creare delle situazioni in cui il codice modificato è così tanto da rendere complicato il controllo da parte dello sviluppatore, che sarebbe tentato di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema, darci indici ci complessità ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. -Ciò nonostante, rimangono degli ottimi aiutanti: se ad essi affidiamo la correzione di tutti quegli "errori" semplici, come la tipizzazione delle variabili (nel caso di linguaggi tipizzati, ovviamente) o la riscrittura di una funzione utilizzando il pattern _Early Return_, ci ritroveremo a dover rifattorizzare del codice già scremato, lasciando la nostra mente libera di concentrarsi sul resto del lavoro da fare. \ No newline at end of file +Ciò nonostante, rimangono degli ottimi aiutanti: se ad essi affidiamo la correzione di tutti quegli "errori" semplici, come la tipizzazione delle variabili (nel caso di linguaggi tipizzati, ovviamente) o la riscrittura di una funzione utilizzando il pattern _Early Return_, ci ritroveremo a dover rifattorizzare del codice già scremato, lasciando la nostra mente libera di concentrarsi sul resto del lavoro da fare. From 8ef246dd366213f38e5ff216539ca13197869a97 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Mon, 19 Feb 2024 09:54:22 +0100 Subject: [PATCH 05/23] chore: rimosso ToC --- docs/it/refactoring.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 940cb401..49689a6f 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -1,12 +1,4 @@ -# Table Of Contents - -- Cos'è il refactoring? -- Quando fare refactoring? -- Quando NON fare refactoring? - -# Altre idee - -- Differenza (Di intenti oltre che di tempo ed effort) tra refactoring automatico e manuale +# Refactor ## Che cos'è il refactoring From ac2e916375b207322529c52021aa6f6f275d10ca Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Sat, 24 Feb 2024 10:54:36 +0100 Subject: [PATCH 06/23] chore: revisione Co-authored-by: Brian Atzori <43118219+BrianAtzori@users.noreply.github.com> --- docs/it/refactoring.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 49689a6f..536b5c35 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -21,10 +21,10 @@ La scrittura del codice non è del tutto lineare, soprattutto se scritto a più Sono diverse le occasioni in cui è possibile fare refactoring e, in alcune di queste, non solo è consigliato ma obbligatorio. Poniamo il caso che abbiamo una parte del nostro software con del codice "legacy", magari scritto rispettando dei pattern che, nel tempo, si sono rivelati sbagliati. Oppure scritto di fretta, senza rispettare i principi SOLID e con metodi e variabili che hanno nomi provvisori. O ancora, il codice scritto risulta difficile da testare, perché presenta metodi o classi poco disaccoppiate. Con metodi privati che non fanno attività atomiche. -Fatta una rapida analisi, notiamo che, magari, ci sono dei cicli ripetuti, o parti di codice che potrebbero essere evitate se solo avessimo posto dei semafori a monte. +Fatta una rapida analisi potremmo notare che magari ci sono dei cicli ripetuti, o parti di codice che potrebbero essere evitate se solo avessimo posto dei semafori a monte. Con del buon refactoring potremmo rivedere il codice, eliminare delle dipendenze inutili o utilizzare dei costrutti del linguaggio più adatti, con il risultato di migliorarne la lettura, aderire agli standard del linguaggio (che, nell'ottica di rendere il nostro codice più condivisibile possibile, non fa mai male) e, perché no, migliorarne le performance e eliminare debito tecnico. Come detto, le occasioni non mancano. -Potremmo cogliere l'occasione di una Code Review o l'aggiunta di una nuova feature. Prima di iniziarne lo sviluppo, sicuramente è buona pratica leggere il codice in cui questa nuova funzionalità andrà a integrarsi e, se quest'ultimo risulta di difficile comprensione, è un'ottima occasione per effettuarne la rifattorizzazione. Questo ci permetterebbe di ottenere una maggiore conoscienza del codice. +Potremmo cogliere l'occasione di una Code Review o l'aggiunta di una nuova feature. Prima di iniziarne lo sviluppo, sicuramente è buona pratica leggere il codice in cui questa nuova funzionalità andrà a integrarsi e, se quest'ultimo risulta di difficile comprensione, è un'ottima occasione per effettuarne il refactoring. Questo ci permetterebbe di ottenere una maggiore conoscenza del codice. Un'altra, forse la migliore, dove è (quasi) obbligatorio, è la risoluzione di un bug in una parte di codice convulso, la cui sola lettura ci fa venire il mal di testa. Un'attività di refactoring potrebbe facilmente portare alla luce l'errore presente nel codice. L'attività di refactoring può essere paragonata a una pulizia profonda di casa, piuttosto che a una routine di sistemazione della propria cameretta, necessaria per mantenere il codice sicuro, di valore ed efficiente. @@ -58,7 +58,7 @@ Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Dr ### Rinominare i metodi oscuri -Ci sono metodi che hanno nomi degni di un codice morse ma che poco dicono sull'operazioni che vanno a intraprendere. +Ci sono metodi che hanno nomi degni di un codice morse ma che poco dicono sulle operazioni che vanno a intraprendere. Un buon inizio potrebbe essere quello di rinominarli in modo che chi legge, abbia la possibilità di capire cosa fa quel metodo senza necessità alcuna di andarlo a verificare. ### Cambiare la firma dei metodi @@ -103,7 +103,7 @@ function applyDiscount() { } ``` -Con questa modifica, non abbiamo modificato in alcun modo il comportamento. Ovviamente, otterremo un piccolo vantaggio sulle performance a patto che, il linguaggio che stiamo usando può trarre vantaggi dalla differenza tra variabili mutabili e non. +Con questa modifica, non abbiamo cambiato in alcun modo il comportamento. Ovviamente otterremo un piccolo vantaggio sulle performance, a patto che il linguaggio che stiamo usando possa trarre vantaggi dalla differenza tra variabili mutabili e non. Ma, riguardando ancora un attimo il codice, potremmo apportare un'altra modifica: ``` @@ -116,7 +116,7 @@ Rimuovendo la creazione di una variabile, che oggettivamente risulta solo superf ## Costi -Lo sviluppo di un software ha un costo, ovviamente anche il refactoring ne ha uno. Ma, fatto con regolarità, sfruttando tutte le occasioni possibili, ovvero effettuando micro-interventi di refactoring, non solo il suo costo è trascurabile ma, complessivamente, abbassa i costi grazie alla maggiore mantenibilità, scalabilità e performance ottenute. +Lo sviluppo di un software ha un costo, ovviamente anche il refactoring ne ha uno. Ma, fatto con regolarità, sfruttando tutte le occasioni possibili, ovvero effettuando micro-interventi di refactoring, non solo il suo costo è trascurabile ma, complessivamente, abbassa i costi grazie alla maggiore manutenibilità, scalabilità e performance ottenute. ## Refactoring vs Riscrittura @@ -126,7 +126,7 @@ Con il refactoring, dove il dictat del non modificare in alcun modo il comportam ## Automazione -Esistono ovviamente diversi strumenti pe automatizzare le procedure di refactoring, spesso integrati direttamente nell'IDE. Forse il più famoso è Sonarqube. +Esistono ovviamente diversi strumenti per automatizzare le procedure di refactoring, spesso integrati direttamente nell'IDE. Forse il più famoso è Sonarqube. Questi strumenti, basati su motori di analisi affidabili e complessi, riescono a individuare dalla banale duplicazione del codice alla mancata adozione di buone pratiche, spesso specifiche del linguaggio di programmazione adottato. A volte riescono a fare miracoli ma, a noi preme focalizzarci su un punto della questione: l'effort. Quanto effort occorre ad effettuare del refactoring con questi strumenti. O meglio, quanto semplificano la vita dello sviluppatore. From afbfb651a270dd5ab353d2a632778f98e66d782b Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Wed, 27 Mar 2024 21:20:44 +0100 Subject: [PATCH 07/23] Apply suggestions from code review Co-authored-by: Paolo Martinoli <81316809+ugho16@users.noreply.github.com> --- docs/it/refactoring.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 536b5c35..e4c70323 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -5,24 +5,24 @@ Alcuni direbbero che il refactoring è l'arte di crearsi problemi. Il refactoring è un insieme di attività dedite a rivedere una o più parti del codice con cui è composta la nostra applicazione. Può interessare un singolo metodo, una singola classe, un intero modulo. -L'obiettivo di queste attività è rivedere la logica piuttosto che la scrittura del codice che la compone, in modo da ottenere migliori performance (o un maggior disaccoppiamento, una maggiore testabilità) senza però, in alcun modo, alterarne il comportamento e, soprattutto, aggiungere nuove funzionalità. +L'obiettivo di queste attività è rivedere la logica oppure la scrittura del codice che la compone, in modo da ottenere migliori performance (o un maggior disaccoppiamento, una maggiore testabilità) senza però, in alcun modo, alterarne il comportamento e, soprattutto, aggiungere nuove funzionalità. Se l'attività è stata fatta bene, al termine avremo un codice più pulito, comprensibile, di cui non è stato alterato il comportamento e che passa perfettamente tutti i test già presenti. Ma andiamo per gradi. ## Benefici Uno dei principali benefici che otterremo con il refactoring è la rimozione di porzioni di codice non performanti, sostituiti da codice più trasparente e chiaro. E con questo, un'evidente riduzione del debito tecnico accumulato. -Un codice scritto bene, non solo aiuta a chi lo ha scritto di poterlo rivedere a distanza di qualche tempo senza troppi mal di testa ma, con il crescere del software e l'introduzione di nuove funzionalità, rende più semplice la vita ai futuri sviluppatori che dovranno interfacciarsi con esso. -Da un codice scritto bene, si possono ottenere migliori performance. Magari non direttamente ma, una buona attività di refactoring ci permetterà di avere molto più chiaro come il software interagisce, dandoci la possibilità di individuare eventuali colli di bottiglia, anche a livello architetturale. +Un codice scritto bene non solo aiuta chi lo ha scritto a poterlo rivedere a distanza di qualche tempo senza troppi mal di testa, ma, con il crescere del software e l'introduzione di nuove funzionalità, rende più semplice la vita a chi in futuro dovrà interfacciarsi con esso. +Da un codice scritto bene si possono ottenere migliori performance. Magari non direttamente, ma una buona attività di refactoring ci permetterà di avere molto più chiaro come il software interagisce, dandoci la possibilità di individuare eventuali colli di bottiglia, anche a livello architetturale. ## Quando -La scrittura del codice non è del tutto lineare, soprattutto se scritto a più mani. Ogni sviluppatore ha un suo stile, delle sue convinzioni, un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. +La scrittura del codice non è del tutto lineare, soprattutto se scritto a più mani. Ogni developer ha un suo stile, delle sue convinzioni, un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. Sono diverse le occasioni in cui è possibile fare refactoring e, in alcune di queste, non solo è consigliato ma obbligatorio. Poniamo il caso che abbiamo una parte del nostro software con del codice "legacy", magari scritto rispettando dei pattern che, nel tempo, si sono rivelati sbagliati. Oppure scritto di fretta, senza rispettare i principi SOLID e con metodi e variabili che hanno nomi provvisori. O ancora, il codice scritto risulta difficile da testare, perché presenta metodi o classi poco disaccoppiate. Con metodi privati che non fanno attività atomiche. Fatta una rapida analisi potremmo notare che magari ci sono dei cicli ripetuti, o parti di codice che potrebbero essere evitate se solo avessimo posto dei semafori a monte. -Con del buon refactoring potremmo rivedere il codice, eliminare delle dipendenze inutili o utilizzare dei costrutti del linguaggio più adatti, con il risultato di migliorarne la lettura, aderire agli standard del linguaggio (che, nell'ottica di rendere il nostro codice più condivisibile possibile, non fa mai male) e, perché no, migliorarne le performance e eliminare debito tecnico. +Con del buon refactoring potremmo rivedere il codice, eliminare delle dipendenze inutili o utilizzare dei costrutti del linguaggio più adatti, con il risultato di migliorarne la lettura, aderire agli standard del linguaggio (che, nell'ottica di rendere il nostro codice più condivisibile possibile, non fa mai male) e, perché no, migliorarne le performance ed eliminare debito tecnico. Come detto, le occasioni non mancano. Potremmo cogliere l'occasione di una Code Review o l'aggiunta di una nuova feature. Prima di iniziarne lo sviluppo, sicuramente è buona pratica leggere il codice in cui questa nuova funzionalità andrà a integrarsi e, se quest'ultimo risulta di difficile comprensione, è un'ottima occasione per effettuarne il refactoring. Questo ci permetterebbe di ottenere una maggiore conoscenza del codice. Un'altra, forse la migliore, dove è (quasi) obbligatorio, è la risoluzione di un bug in una parte di codice convulso, la cui sola lettura ci fa venire il mal di testa. Un'attività di refactoring potrebbe facilmente portare alla luce l'errore presente nel codice. @@ -50,7 +50,7 @@ Per farlo, potremmo iniziare con: ### Red-Green-Refactor -Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Driven Development), dove lo sviluppatore suddivide il processo di scrittura del codice in tre fasi: +Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Driven Development), dove chi sviluppa suddivide il processo di scrittura del codice in tre fasi: - Analizza quali sono le esigenze e scrive dapprima il test, che, per ovvi motivi, fallirà (_Red_); - Scrive il codice necessario affinché il test passi (_Green_); @@ -59,13 +59,13 @@ Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Dr ### Rinominare i metodi oscuri Ci sono metodi che hanno nomi degni di un codice morse ma che poco dicono sulle operazioni che vanno a intraprendere. -Un buon inizio potrebbe essere quello di rinominarli in modo che chi legge, abbia la possibilità di capire cosa fa quel metodo senza necessità alcuna di andarlo a verificare. +Un buon inizio potrebbe essere quello di rinominarli in modo che chi legge abbia la possibilità di capire cosa fa quel metodo, senza necessità alcuna di andarlo a verificare. ### Cambiare la firma dei metodi Partendo dal presupposto che il codice è vivo, si ci può trovare nelle condizioni in cui al metodo inizialmente venivano passate diverse informazioni, che magari ora non sono più necessarie. E magari non lo sono perché nel frattempo, quella parte di codice era stata già snellita in qualche attività precedente. Possiamo quindi rimuovere le informazioni in eccesso, modificandone la firma. -Inoltre, potremmo verificare, nei linguaggi tipizzati, se c'è la possibilità di rendere detta firma più stringente, ammettendo e/o restituendo tipi meno generici. +Inoltre, nei linguaggi tipizzati, potremmo verificare se c'è la possibilità di rendere detta firma più stringente, ammettendo e/o restituendo tipi meno generici. ### Estrarre nuovi metodi @@ -80,12 +80,12 @@ In questo caso, sarà necessario intervenire dapprima sul rendere meno complesso ### Astrarre -Spesso, molte delle classi o dei metodi che vengono creati, hanno qualche parte di codice in comune, come le firme dei metodi o l'inizializzazione del contesto. +Spesso, molte delle classi o dei metodi che vengono creati hanno qualche parte di codice in comune, come le firme dei metodi o l'inizializzazione del contesto. Sebbene questo potrebbe non essere sempre possibile, dopo avere estratto i metodi, ci potremmo trovare dinanzi a molti di questi che sono simili se non uguali. Con l'astrazione possiamo creare delle classi che contengono tali metodi. Metodi che potrebbero divenire ancora più semplici e generici, nonchè facili da interpretare. ## Un Esempio -Un caso semplice ma spesso presente nel nostro codice, potrebbe essere quello di migliorare le performance rimuovendo le variabili temporanee (il codice che segue è pseudo-codice): +Un caso semplice, ma spesso presente nel nostro codice, potrebbe essere quello di migliorare le performance rimuovendo le variabili temporanee (il codice che segue è pseudo-codice): ``` function applyDiscount() { @@ -103,7 +103,7 @@ function applyDiscount() { } ``` -Con questa modifica, non abbiamo cambiato in alcun modo il comportamento. Ovviamente otterremo un piccolo vantaggio sulle performance, a patto che il linguaggio che stiamo usando possa trarre vantaggi dalla differenza tra variabili mutabili e non. +Con questa modifica non abbiamo cambiato in alcun modo il comportamento. Ovviamente otterremo un piccolo vantaggio sulle performance, a patto che il linguaggio che stiamo usando possa trarre vantaggi dalla differenza tra variabili mutabili e non. Ma, riguardando ancora un attimo il codice, potremmo apportare un'altra modifica: ``` @@ -128,9 +128,9 @@ Con il refactoring, dove il dictat del non modificare in alcun modo il comportam Esistono ovviamente diversi strumenti per automatizzare le procedure di refactoring, spesso integrati direttamente nell'IDE. Forse il più famoso è Sonarqube. Questi strumenti, basati su motori di analisi affidabili e complessi, riescono a individuare dalla banale duplicazione del codice alla mancata adozione di buone pratiche, spesso specifiche del linguaggio di programmazione adottato. -A volte riescono a fare miracoli ma, a noi preme focalizzarci su un punto della questione: l'effort. -Quanto effort occorre ad effettuare del refactoring con questi strumenti. O meglio, quanto semplificano la vita dello sviluppatore. +A volte riescono a fare miracoli, ma a noi preme focalizzarci su un punto della questione: l'effort. +Quanto effort occorre ad effettuare del refactoring con questi strumenti. O meglio, quanto semplificano la vita di chi sviluppa. È innegabile che sono dei validi aiuti e che sono formidabili nel farci notare parti di codice da semplificare a cui, magari, non avevamo nemmeno fatto caso. -Ma, affidare il refactoring all'automazione, può creare delle situazioni in cui il codice modificato è così tanto da rendere complicato il controllo da parte dello sviluppatore, che sarebbe tentato di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. -C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema, darci indici ci complessità ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. +Tuttavia, affidare il refactoring all'automazione può creare delle situazioni in cui il codice modificato è così tanto da rendere complicato il controllo da parte di chi sviluppa, tanto che potrebbe avere la tentazione di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. +C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema, darci indici di complessità ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. Ciò nonostante, rimangono degli ottimi aiutanti: se ad essi affidiamo la correzione di tutti quegli "errori" semplici, come la tipizzazione delle variabili (nel caso di linguaggi tipizzati, ovviamente) o la riscrittura di una funzione utilizzando il pattern _Early Return_, ci ritroveremo a dover rifattorizzare del codice già scremato, lasciando la nostra mente libera di concentrarsi sul resto del lavoro da fare. From ea5b4d31f4c83c9722d46523d2fcc8be3be54e76 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Fri, 5 Apr 2024 21:43:06 +0200 Subject: [PATCH 08/23] Apply suggestions from code review Co-authored-by: Angelo Cassano --- docs/it/refactoring.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index e4c70323..ed86b8e5 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -3,7 +3,7 @@ ## Che cos'è il refactoring Alcuni direbbero che il refactoring è l'arte di crearsi problemi. -Il refactoring è un insieme di attività dedite a rivedere una o più parti del codice con cui è composta la nostra applicazione. +Il refactoring è un insieme di attività dedite alla revisione di una o più parti del codice di cui è composta la nostra applicazione. Può interessare un singolo metodo, una singola classe, un intero modulo. L'obiettivo di queste attività è rivedere la logica oppure la scrittura del codice che la compone, in modo da ottenere migliori performance (o un maggior disaccoppiamento, una maggiore testabilità) senza però, in alcun modo, alterarne il comportamento e, soprattutto, aggiungere nuove funzionalità. Se l'attività è stata fatta bene, al termine avremo un codice più pulito, comprensibile, di cui non è stato alterato il comportamento e che passa perfettamente tutti i test già presenti. @@ -12,14 +12,14 @@ Ma andiamo per gradi. ## Benefici Uno dei principali benefici che otterremo con il refactoring è la rimozione di porzioni di codice non performanti, sostituiti da codice più trasparente e chiaro. E con questo, un'evidente riduzione del debito tecnico accumulato. -Un codice scritto bene non solo aiuta chi lo ha scritto a poterlo rivedere a distanza di qualche tempo senza troppi mal di testa, ma, con il crescere del software e l'introduzione di nuove funzionalità, rende più semplice la vita a chi in futuro dovrà interfacciarsi con esso. +Un codice scritto bene non solo aiuta chi lo ha scritto a poterlo rivedere a distanza di tempo senza troppi mal di testa ma, con il crescere del software e l'introduzione di nuove funzionalità, rende più semplice la vita a chi in futuro dovrà interfacciarsi con esso. Da un codice scritto bene si possono ottenere migliori performance. Magari non direttamente, ma una buona attività di refactoring ci permetterà di avere molto più chiaro come il software interagisce, dandoci la possibilità di individuare eventuali colli di bottiglia, anche a livello architetturale. ## Quando -La scrittura del codice non è del tutto lineare, soprattutto se scritto a più mani. Ogni developer ha un suo stile, delle sue convinzioni, un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. +La scrittura del codice non è del tutto lineare, soprattutto se fatta a più mani. Ogni developer ha un suo stile, delle sue convenzioni, un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. Sono diverse le occasioni in cui è possibile fare refactoring e, in alcune di queste, non solo è consigliato ma obbligatorio. -Poniamo il caso che abbiamo una parte del nostro software con del codice "legacy", magari scritto rispettando dei pattern che, nel tempo, si sono rivelati sbagliati. Oppure scritto di fretta, senza rispettare i principi SOLID e con metodi e variabili che hanno nomi provvisori. +Poniamo il caso di avere una parte del nostro software con del codice "legacy", magari scritto rispettando dei pattern che, nel tempo, si sono rivelati sbagliati. Oppure scritto di fretta, senza rispettare i principi SOLID e con metodi e variabili che hanno nomi provvisori. O ancora, il codice scritto risulta difficile da testare, perché presenta metodi o classi poco disaccoppiate. Con metodi privati che non fanno attività atomiche. Fatta una rapida analisi potremmo notare che magari ci sono dei cicli ripetuti, o parti di codice che potrebbero essere evitate se solo avessimo posto dei semafori a monte. Con del buon refactoring potremmo rivedere il codice, eliminare delle dipendenze inutili o utilizzare dei costrutti del linguaggio più adatti, con il risultato di migliorarne la lettura, aderire agli standard del linguaggio (che, nell'ottica di rendere il nostro codice più condivisibile possibile, non fa mai male) e, perché no, migliorarne le performance ed eliminare debito tecnico. @@ -32,7 +32,7 @@ L'attività di refactoring può essere paragonata a una pulizia profonda di casa Non sempre è utile effettuare refactoring. Ci sono casi in cui il codice è già perfettamente ottimizzato anche se, a una vista inesperta, potrebbe risultare di difficile lettura. -Ci sono casi in cui le performance sono fondamentali e i principi SOLID non sono sempre rispettati. In questo caso, il refactoring ci porterebbe a creare dei layer aggiuntivi di codice che, sebbene ci renderebbe il codice più comprensibile, avrebbe un impatto negativo sulle performance. Un esempio sono le librerie che permettono le connessioni con delle basi di dati, dove magari è fondamentale la gestione della latenza. +Ci sono casi in cui le performance sono fondamentali e i principi SOLID non sono sempre rispettati. In questo caso, il refactoring ci porterebbe a creare dei layer aggiuntivi di codice che, sebbene possa rendere il codice più comprensibile, avrebbe un impatto negativo sulle performance. Un esempio sono le librerie che permettono le connessioni con delle basi di dati, dove magari è fondamentale la gestione della latenza. In questi casi, ma più in generale, è necessario tenere a mente che l'attività di refactoring ha tra gli obiettivi quello di rivedere il codice rendendolo più mantenibile, nonché rifattorizzabile. Diretta conseguenza di questo obiettivo, è la sua applicazione nella pratica del TDD (Test Driven Development), dove il refactoring copre uno degli step. @@ -41,20 +41,20 @@ Diretta conseguenza di questo obiettivo, è la sua applicazione nella pratica de Come si può intuire, con le attività di refactoring andremo a migliorare il codice in modo da renderlo meno complesso, più mantenibile, più resiliente. Per farlo, potremmo iniziare con: -- Red-Green-Refactor; -- Rinominare i metodi oscuri; -- Cambiare la firma dei metodi; -- Estrarre nuovi metodi; -- Semplificare i metodi esistenti; -- Astrarre. +* Red-Green-Refactor; +* Rinominare i metodi oscuri; +* Cambiare la firma dei metodi; +* Estrarre nuovi metodi; +* Semplificare i metodi esistenti; +* Astrarre. ### Red-Green-Refactor Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Driven Development), dove chi sviluppa suddivide il processo di scrittura del codice in tre fasi: -- Analizza quali sono le esigenze e scrive dapprima il test, che, per ovvi motivi, fallirà (_Red_); -- Scrive il codice necessario affinché il test passi (_Green_); -- Lo migliora (_Refactoring_) +* Analizza quali sono le esigenze e scrive dapprima il test, che, per ovvi motivi, fallirà (_Red_); +* Scrive il codice necessario affinché il test passi (_Green_); +* Lo migliora (_Refactoring_) ### Rinominare i metodi oscuri @@ -81,7 +81,7 @@ In questo caso, sarà necessario intervenire dapprima sul rendere meno complesso ### Astrarre Spesso, molte delle classi o dei metodi che vengono creati hanno qualche parte di codice in comune, come le firme dei metodi o l'inizializzazione del contesto. -Sebbene questo potrebbe non essere sempre possibile, dopo avere estratto i metodi, ci potremmo trovare dinanzi a molti di questi che sono simili se non uguali. Con l'astrazione possiamo creare delle classi che contengono tali metodi. Metodi che potrebbero divenire ancora più semplici e generici, nonchè facili da interpretare. +Sebbene questo potrebbe non essere sempre possibile, dopo avere estratto i metodi, ci potremmo trovare dinanzi a funzioni con comportamenti sovrapponibili. Con l'astrazione possiamo creare delle classi che contengono tali metodi. Metodi che potrebbero divenire ancora più semplici e generici, nonché facili da interpretare. ## Un Esempio @@ -116,7 +116,7 @@ Rimuovendo la creazione di una variabile, che oggettivamente risulta solo superf ## Costi -Lo sviluppo di un software ha un costo, ovviamente anche il refactoring ne ha uno. Ma, fatto con regolarità, sfruttando tutte le occasioni possibili, ovvero effettuando micro-interventi di refactoring, non solo il suo costo è trascurabile ma, complessivamente, abbassa i costi grazie alla maggiore manutenibilità, scalabilità e performance ottenute. +Lo sviluppo di un software ha un costo, ovviamente anche il refactoring ne ha uno. Ma, fatto con regolarità, sfruttando tutte le occasioni possibili, ovvero effettuando micro-interventi di refactoring, non solo il suo costo tende a diventare trascurabile ma, complessivamente, abbassa i costi grazie alla maggiore manutenibilità, scalabilità e performance ottenute. ## Refactoring vs Riscrittura @@ -129,8 +129,8 @@ Con il refactoring, dove il dictat del non modificare in alcun modo il comportam Esistono ovviamente diversi strumenti per automatizzare le procedure di refactoring, spesso integrati direttamente nell'IDE. Forse il più famoso è Sonarqube. Questi strumenti, basati su motori di analisi affidabili e complessi, riescono a individuare dalla banale duplicazione del codice alla mancata adozione di buone pratiche, spesso specifiche del linguaggio di programmazione adottato. A volte riescono a fare miracoli, ma a noi preme focalizzarci su un punto della questione: l'effort. -Quanto effort occorre ad effettuare del refactoring con questi strumenti. O meglio, quanto semplificano la vita di chi sviluppa. +Quanto effort occorre ad effettuare del refactoring con questi strumenti? O meglio, quanto semplificano la vita di chi sviluppa? È innegabile che sono dei validi aiuti e che sono formidabili nel farci notare parti di codice da semplificare a cui, magari, non avevamo nemmeno fatto caso. -Tuttavia, affidare il refactoring all'automazione può creare delle situazioni in cui il codice modificato è così tanto da rendere complicato il controllo da parte di chi sviluppa, tanto che potrebbe avere la tentazione di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. -C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema, darci indici di complessità ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. +Tuttavia, affidare il refactoring all'automazione può creare delle situazioni in cui il codice modificato è così tanto, da rendere complicato il controllo da parte di chi sviluppa, tanto che potrebbe avere la tentazione di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. +C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema e a darci indici di complessità. ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. Ciò nonostante, rimangono degli ottimi aiutanti: se ad essi affidiamo la correzione di tutti quegli "errori" semplici, come la tipizzazione delle variabili (nel caso di linguaggi tipizzati, ovviamente) o la riscrittura di una funzione utilizzando il pattern _Early Return_, ci ritroveremo a dover rifattorizzare del codice già scremato, lasciando la nostra mente libera di concentrarsi sul resto del lavoro da fare. From 55aaaf48ebc5559c4989a560b1964c0668b3dffe Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Sat, 6 Apr 2024 11:32:29 +0200 Subject: [PATCH 09/23] Update docs/it/refactoring.md --- docs/it/refactoring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index ed86b8e5..c2ebf2fc 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -17,7 +17,7 @@ Da un codice scritto bene si possono ottenere migliori performance. Magari non d ## Quando -La scrittura del codice non è del tutto lineare, soprattutto se fatta a più mani. Ogni developer ha un suo stile, delle sue convenzioni, un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. +La scrittura del codice non è del tutto lineare, soprattutto se fatta a più mani. Ogni developer ha un suo stile, delle sue convinzioni, un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. Sono diverse le occasioni in cui è possibile fare refactoring e, in alcune di queste, non solo è consigliato ma obbligatorio. Poniamo il caso di avere una parte del nostro software con del codice "legacy", magari scritto rispettando dei pattern che, nel tempo, si sono rivelati sbagliati. Oppure scritto di fretta, senza rispettare i principi SOLID e con metodi e variabili che hanno nomi provvisori. O ancora, il codice scritto risulta difficile da testare, perché presenta metodi o classi poco disaccoppiate. Con metodi privati che non fanno attività atomiche. From 6f2828b43bfc226c61f8cdf522325fe08af4b885 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Sat, 11 May 2024 11:51:09 +0200 Subject: [PATCH 10/23] Apply suggestions from code review Co-authored-by: Brian Atzori <43118219+BrianAtzori@users.noreply.github.com> --- docs/it/refactoring.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index c2ebf2fc..f6138b19 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -17,7 +17,7 @@ Da un codice scritto bene si possono ottenere migliori performance. Magari non d ## Quando -La scrittura del codice non è del tutto lineare, soprattutto se fatta a più mani. Ogni developer ha un suo stile, delle sue convinzioni, un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. +La scrittura del codice non è del tutto lineare, soprattutto se fatta a più mani. Ogni developer ha un suo stile, delle sue convinzioni e un determinato livello di preparazione. Questo porta spesso ad avere del codice, scritto a colpi di commit, funzionante ma difficile da comprendere, con scorciatoie evitabili, metodi prolissi o, peggio ancora, costanti che non dovrebbero esserlo. Sono diverse le occasioni in cui è possibile fare refactoring e, in alcune di queste, non solo è consigliato ma obbligatorio. Poniamo il caso di avere una parte del nostro software con del codice "legacy", magari scritto rispettando dei pattern che, nel tempo, si sono rivelati sbagliati. Oppure scritto di fretta, senza rispettare i principi SOLID e con metodi e variabili che hanno nomi provvisori. O ancora, il codice scritto risulta difficile da testare, perché presenta metodi o classi poco disaccoppiate. Con metodi privati che non fanno attività atomiche. @@ -25,7 +25,7 @@ Fatta una rapida analisi potremmo notare che magari ci sono dei cicli ripetuti, Con del buon refactoring potremmo rivedere il codice, eliminare delle dipendenze inutili o utilizzare dei costrutti del linguaggio più adatti, con il risultato di migliorarne la lettura, aderire agli standard del linguaggio (che, nell'ottica di rendere il nostro codice più condivisibile possibile, non fa mai male) e, perché no, migliorarne le performance ed eliminare debito tecnico. Come detto, le occasioni non mancano. Potremmo cogliere l'occasione di una Code Review o l'aggiunta di una nuova feature. Prima di iniziarne lo sviluppo, sicuramente è buona pratica leggere il codice in cui questa nuova funzionalità andrà a integrarsi e, se quest'ultimo risulta di difficile comprensione, è un'ottima occasione per effettuarne il refactoring. Questo ci permetterebbe di ottenere una maggiore conoscenza del codice. -Un'altra, forse la migliore, dove è (quasi) obbligatorio, è la risoluzione di un bug in una parte di codice convulso, la cui sola lettura ci fa venire il mal di testa. Un'attività di refactoring potrebbe facilmente portare alla luce l'errore presente nel codice. +Un'altra occasione potrebbe essere la risoluzione di un bug in una porzione di codice complessa, la cui sola lettura ci fa venire il mal di testa. Un'attività di refactoring potrebbe facilmente portare alla luce l'errore presente nel codice, e spesso risulta la strada migliore, in quanto porta non solo ad una risoluzione, ma anche ad un codice migliore e più mantenibile in futuro, riducendo il rischio di regressioni. L'attività di refactoring può essere paragonata a una pulizia profonda di casa, piuttosto che a una routine di sistemazione della propria cameretta, necessaria per mantenere il codice sicuro, di valore ed efficiente. ## Quando è meglio evitare From 0e6a9e2c8da5fd6052cad9f1c650403b73a61397 Mon Sep 17 00:00:00 2001 From: Mario Ravalli Date: Sat, 11 May 2024 16:30:47 +0200 Subject: [PATCH 11/23] Aggiunto un esempio e rivisto un passaggio che risultava poco chiaro --- docs/it/refactoring.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index f6138b19..1c973921 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -60,6 +60,26 @@ Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Dr Ci sono metodi che hanno nomi degni di un codice morse ma che poco dicono sulle operazioni che vanno a intraprendere. Un buon inizio potrebbe essere quello di rinominarli in modo che chi legge abbia la possibilità di capire cosa fa quel metodo, senza necessità alcuna di andarlo a verificare. +Prendiamo ad esempio questo metodo: + +``` +function getNetto() { + basePrice = cart.totalPrice(); + return basePrice * discount(); +} +``` + +Leggendone il contenuto è chiaro che ci sta tornando il totale del carrello al netto di eventuali sconti ma, senza conoscerne il contenuto, come facciamo a esserne sicuri? +Proviamo quindi a rinominarlo con qualcosa di più "parlante". + +``` +function applyDiscount() { + basePrice = cart.totalPrice(); + return basePrice * discount(); +} +``` + +Cambiandone il nome, abbiamo reso più chiaro cosa farà e rendiamo più semplice la vita a chi quel metodo dovrà usarlo. ### Cambiare la firma dei metodi @@ -120,9 +140,13 @@ Lo sviluppo di un software ha un costo, ovviamente anche il refactoring ne ha un ## Refactoring vs Riscrittura -Si potrebbe obiettare che riscrivere una parte del nostro software, basandosi sull'esperienza acquisita, è più veloce o forse più auspicabile del refactoring. -In realtà questa affermazione è fallace: riscrivere significa affrontare un'attività che comporta del tempo non sempre definito, che apporta delle modifiche al funzionamento del software, che andrà testato probabilmente con dei nuovi test e che, non da ultimo, andrà rilasciato in blocco. -Con il refactoring, dove il dictat del non modificare in alcun modo il comportamento ci impone che i test devono continuare a funzionare senza alcun nostro intervento, è un'attività contingentata che può essere fatta durante lo sviluppo di una nuova funzionalità, se non durante la scrittura dei test stessi. E, soprattutto, il lavoro può essere rilasciato durante il normale ciclo di vita del software, annegato tra i vari rilasci e/o correzioni. +Riscrivere tutto da capo o rivedere il lavoro fatto: un bel dilemma. +Quando ci si trova davanti a del codice che necessita di refactoring a tutti è sorto il dubbio: ma non faccio prima a riscriverlo da capo? Questa domanda ce la poniamo, in genere, perché, basandoci sull'esperienza acquisita, ci convinciamo che saremmo più veloci a riscrivere tutto e otterremmo un risultato decisamente migliore. Ma, forse, non stiamo tenendo conto di due fattori fondamentali: + +* non dobbiamo alterare il comportamento attuale, i test debbono restare inalterati; +* il nuovo codice dovrebbe andare incontro a successive revisioni e riscritture, se non nuovi test. + +Il refactoring è un'attività contingentata che chi permette di guardare con distacco al nostro stesso codice, dandoci la possibilità di migliorarlo proprio alla luce dell'esperienza acquisita. E, imponendoci l'immutabilità delle firme nonché il rispetto dei test attuali, ci permette inoltre di poter rilasciare il nuovo codice con molta più tranquillità. ## Automazione From b33d3e7bb07fbd78dc9e47b6275572055aee29e3 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Mon, 13 May 2024 13:00:46 +0200 Subject: [PATCH 12/23] Apply suggestions from code review --- docs/it/refactoring.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 1c973921..6679ffce 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -73,7 +73,7 @@ Leggendone il contenuto è chiaro che ci sta tornando il totale del carrello al Proviamo quindi a rinominarlo con qualcosa di più "parlante". ``` -function applyDiscount() { +function getAmountWithAppliedDiscount() { basePrice = cart.totalPrice(); return basePrice * discount(); } @@ -141,12 +141,13 @@ Lo sviluppo di un software ha un costo, ovviamente anche il refactoring ne ha un ## Refactoring vs Riscrittura Riscrivere tutto da capo o rivedere il lavoro fatto: un bel dilemma. -Quando ci si trova davanti a del codice che necessita di refactoring a tutti è sorto il dubbio: ma non faccio prima a riscriverlo da capo? Questa domanda ce la poniamo, in genere, perché, basandoci sull'esperienza acquisita, ci convinciamo che saremmo più veloci a riscrivere tutto e otterremmo un risultato decisamente migliore. Ma, forse, non stiamo tenendo conto di due fattori fondamentali: +Quando ci si trova davanti a del codice che necessita di refactoring a tutti è sorto il dubbio: "ma non faccio prima a riscriverlo da capo?" +Questa domanda ce la poniamo, in genere, perché, basandoci sull'esperienza acquisita, ci convinciamo che saremmo più veloci a riscrivere tutto e otterremmo un risultato decisamente migliore. Ma, forse, non stiamo tenendo conto di due fattori fondamentali: -* non dobbiamo alterare il comportamento attuale, i test debbono restare inalterati; -* il nuovo codice dovrebbe andare incontro a successive revisioni e riscritture, se non nuovi test. +- L'attività di refactoring non dovrebbe alterare il comportamento attuale, e lo stesso dovrebbe valere per i test. +- Scrivendo nuovo codice, potremmo andare incontro a successive revisioni e riscritture, e avremmo necessità di scrivere nuovi test. -Il refactoring è un'attività contingentata che chi permette di guardare con distacco al nostro stesso codice, dandoci la possibilità di migliorarlo proprio alla luce dell'esperienza acquisita. E, imponendoci l'immutabilità delle firme nonché il rispetto dei test attuali, ci permette inoltre di poter rilasciare il nuovo codice con molta più tranquillità. +Il refactoring è un'attività contingentata che ci permette di guardare con distacco al nostro stesso codice, dandoci la possibilità di migliorarlo proprio alla luce dell'esperienza acquisita. E, imponendoci l'immutabilità delle firme nonché il rispetto dei test attuali, ci permette inoltre di poter rilasciare il nuovo codice con molta più tranquillità. ## Automazione From 4e253c97efdc2644e79e205e600c5828d68a1165 Mon Sep 17 00:00:00 2001 From: Mario Ravalli Date: Mon, 13 May 2024 22:48:39 +0200 Subject: [PATCH 13/23] Rivisto il passaggio sul cambiare la firma di un metodo, ponendo l'accento anche sulle controindicazioni --- docs/it/refactoring.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 6679ffce..1ca7450c 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -83,9 +83,12 @@ Cambiandone il nome, abbiamo reso più chiaro cosa farà e rendiamo più semplic ### Cambiare la firma dei metodi -Partendo dal presupposto che il codice è vivo, si ci può trovare nelle condizioni in cui al metodo inizialmente venivano passate diverse informazioni, che magari ora non sono più necessarie. E magari non lo sono perché nel frattempo, quella parte di codice era stata già snellita in qualche attività precedente. -Possiamo quindi rimuovere le informazioni in eccesso, modificandone la firma. -Inoltre, nei linguaggi tipizzati, potremmo verificare se c'è la possibilità di rendere detta firma più stringente, ammettendo e/o restituendo tipi meno generici. +Partendo dal presupposto che il codice è vivo, si possono verificare dei casi in cui un metodo riceva più informazioni del necessario. +Ad esempio potremmo avere un metodo che, nella prima stesura, aveva necessità di numerose informazioni, ma, con successive riscritture, alcune di queste risultaino superflue e non utilizzate. +Oppure, un altro esempio potrebbe essere quello in cui gli passiamo numerose informazioni che potrebbero diventare proprietà di uno o più aggregati. Questo è particolarmente vero nei linguaggi tipizzati, dove potremmo verificare la possibilità di rendere detta firma più stringente, aggregando e/o restituendo tipi meno generici. +In questi casi, possiamo rimuovere le informazioni in eccesso piuttosto che sostituirle con nuovi formati, modificando di fatto la firma del metodo. +C'è però da prestare particolare attenzione a questa pratica: se modificare la firma su un piccolo progetto personale è quasi privo di controindicazioni, farlo su un ambiente su cui lavorano più persone o da cui dipendono altri software su cui non abbiamo modo di intervenire, può creare non pochi problemi. Prendete il caso di una libreria utilizzata da più team: il cambiamento di una singola firma causerebbe il mancato funzionamento di tutti i software che dipendono da essa. +Questo non significa che non sia possibile farlo ma che bisogna agire con maggiore cautela, adottando un giusto percorso di _deprecation_. Deprecare una firma, o parte di essa, indicando quando quella firma stessa terminerà di funzionare e quale alternative adottare, dando quindi la possibilità a chi utilizza il nostro software e quel metodo in particolare di adeguarsi, è di sicuro la strada da seguire. ### Estrarre nuovi metodi From b9876a4506e15b3249d87dac2c9fc46ee5679005 Mon Sep 17 00:00:00 2001 From: Mario Ravalli Date: Mon, 13 May 2024 22:55:41 +0200 Subject: [PATCH 14/23] Run prettier to fix formatting --- docs/it/refactoring.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 1ca7450c..b79066b8 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -41,20 +41,20 @@ Diretta conseguenza di questo obiettivo, è la sua applicazione nella pratica de Come si può intuire, con le attività di refactoring andremo a migliorare il codice in modo da renderlo meno complesso, più mantenibile, più resiliente. Per farlo, potremmo iniziare con: -* Red-Green-Refactor; -* Rinominare i metodi oscuri; -* Cambiare la firma dei metodi; -* Estrarre nuovi metodi; -* Semplificare i metodi esistenti; -* Astrarre. +- Red-Green-Refactor; +- Rinominare i metodi oscuri; +- Cambiare la firma dei metodi; +- Estrarre nuovi metodi; +- Semplificare i metodi esistenti; +- Astrarre. ### Red-Green-Refactor Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Driven Development), dove chi sviluppa suddivide il processo di scrittura del codice in tre fasi: -* Analizza quali sono le esigenze e scrive dapprima il test, che, per ovvi motivi, fallirà (_Red_); -* Scrive il codice necessario affinché il test passi (_Green_); -* Lo migliora (_Refactoring_) +- Analizza quali sono le esigenze e scrive dapprima il test, che, per ovvi motivi, fallirà (_Red_); +- Scrive il codice necessario affinché il test passi (_Green_); +- Lo migliora (_Refactoring_) ### Rinominare i metodi oscuri @@ -149,7 +149,7 @@ Questa domanda ce la poniamo, in genere, perché, basandoci sull'esperienza acqu - L'attività di refactoring non dovrebbe alterare il comportamento attuale, e lo stesso dovrebbe valere per i test. - Scrivendo nuovo codice, potremmo andare incontro a successive revisioni e riscritture, e avremmo necessità di scrivere nuovi test. - + Il refactoring è un'attività contingentata che ci permette di guardare con distacco al nostro stesso codice, dandoci la possibilità di migliorarlo proprio alla luce dell'esperienza acquisita. E, imponendoci l'immutabilità delle firme nonché il rispetto dei test attuali, ci permette inoltre di poter rilasciare il nuovo codice con molta più tranquillità. ## Automazione From 6b060c767492119b59aa7185c95d86e7785924e4 Mon Sep 17 00:00:00 2001 From: Mario Ravalli <11656366+mrkrash@users.noreply.github.com> Date: Sun, 19 May 2024 22:13:53 +0200 Subject: [PATCH 15/23] Update docs/it/refactoring.md Co-authored-by: Michael Di Prisco --- docs/it/refactoring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index b79066b8..e7da1af8 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -84,7 +84,7 @@ Cambiandone il nome, abbiamo reso più chiaro cosa farà e rendiamo più semplic ### Cambiare la firma dei metodi Partendo dal presupposto che il codice è vivo, si possono verificare dei casi in cui un metodo riceva più informazioni del necessario. -Ad esempio potremmo avere un metodo che, nella prima stesura, aveva necessità di numerose informazioni, ma, con successive riscritture, alcune di queste risultaino superflue e non utilizzate. +Ad esempio potremmo avere un metodo che, nella prima stesura, aveva necessità di numerose informazioni, ma, con successive riscritture, alcune di queste risultino superflue e non utilizzate. Oppure, un altro esempio potrebbe essere quello in cui gli passiamo numerose informazioni che potrebbero diventare proprietà di uno o più aggregati. Questo è particolarmente vero nei linguaggi tipizzati, dove potremmo verificare la possibilità di rendere detta firma più stringente, aggregando e/o restituendo tipi meno generici. In questi casi, possiamo rimuovere le informazioni in eccesso piuttosto che sostituirle con nuovi formati, modificando di fatto la firma del metodo. C'è però da prestare particolare attenzione a questa pratica: se modificare la firma su un piccolo progetto personale è quasi privo di controindicazioni, farlo su un ambiente su cui lavorano più persone o da cui dipendono altri software su cui non abbiamo modo di intervenire, può creare non pochi problemi. Prendete il caso di una libreria utilizzata da più team: il cambiamento di una singola firma causerebbe il mancato funzionamento di tutti i software che dipendono da essa. From f7eca6a585689d72063d0b3a9eeab0b855e5a18e Mon Sep 17 00:00:00 2001 From: Mario Ravalli <11656366+mrkrash@users.noreply.github.com> Date: Sun, 19 May 2024 22:14:46 +0200 Subject: [PATCH 16/23] Update docs/it/refactoring.md Co-authored-by: Michael Di Prisco --- docs/it/refactoring.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index e7da1af8..69e5c539 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -85,7 +85,13 @@ Cambiandone il nome, abbiamo reso più chiaro cosa farà e rendiamo più semplic Partendo dal presupposto che il codice è vivo, si possono verificare dei casi in cui un metodo riceva più informazioni del necessario. Ad esempio potremmo avere un metodo che, nella prima stesura, aveva necessità di numerose informazioni, ma, con successive riscritture, alcune di queste risultino superflue e non utilizzate. -Oppure, un altro esempio potrebbe essere quello in cui gli passiamo numerose informazioni che potrebbero diventare proprietà di uno o più aggregati. Questo è particolarmente vero nei linguaggi tipizzati, dove potremmo verificare la possibilità di rendere detta firma più stringente, aggregando e/o restituendo tipi meno generici. +Un altro caso può essere quello in cui un metodo necessiti di numerose informazioni che potrebbero essere accorpati in uno o più aggregati. Questo è particolarmente vero nei linguaggi tipizzati, dove potremmo verificare la possibilità di rendere detta firma più stringente, aggregando e/o restituendo tipi meno generici. + +Prendiamo ad esempio la seguente funzione: +`function updateAddress(userId: number, street: string, city: string, zipCode: string, country: string): void {}` + +Questa funzione potrebbe essere semplificata tramite l'introduzione di un aggregato/tipo `Address` che possa racchiudere al proprio interno tutte le informazioni necessarie: +`function updateAddress(userId: number, address: Address): void {}` In questi casi, possiamo rimuovere le informazioni in eccesso piuttosto che sostituirle con nuovi formati, modificando di fatto la firma del metodo. C'è però da prestare particolare attenzione a questa pratica: se modificare la firma su un piccolo progetto personale è quasi privo di controindicazioni, farlo su un ambiente su cui lavorano più persone o da cui dipendono altri software su cui non abbiamo modo di intervenire, può creare non pochi problemi. Prendete il caso di una libreria utilizzata da più team: il cambiamento di una singola firma causerebbe il mancato funzionamento di tutti i software che dipendono da essa. Questo non significa che non sia possibile farlo ma che bisogna agire con maggiore cautela, adottando un giusto percorso di _deprecation_. Deprecare una firma, o parte di essa, indicando quando quella firma stessa terminerà di funzionare e quale alternative adottare, dando quindi la possibilità a chi utilizza il nostro software e quel metodo in particolare di adeguarsi, è di sicuro la strada da seguire. From 47f174120e1da6a9c3c5d4c1ce637438240667f9 Mon Sep 17 00:00:00 2001 From: Mario Ravalli <11656366+mrkrash@users.noreply.github.com> Date: Sun, 19 May 2024 22:15:31 +0200 Subject: [PATCH 17/23] Update docs/it/refactoring.md Co-authored-by: Michael Di Prisco --- docs/it/refactoring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 69e5c539..9cfe520a 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -94,7 +94,7 @@ Questa funzione potrebbe essere semplificata tramite l'introduzione di un aggreg `function updateAddress(userId: number, address: Address): void {}` In questi casi, possiamo rimuovere le informazioni in eccesso piuttosto che sostituirle con nuovi formati, modificando di fatto la firma del metodo. C'è però da prestare particolare attenzione a questa pratica: se modificare la firma su un piccolo progetto personale è quasi privo di controindicazioni, farlo su un ambiente su cui lavorano più persone o da cui dipendono altri software su cui non abbiamo modo di intervenire, può creare non pochi problemi. Prendete il caso di una libreria utilizzata da più team: il cambiamento di una singola firma causerebbe il mancato funzionamento di tutti i software che dipendono da essa. -Questo non significa che non sia possibile farlo ma che bisogna agire con maggiore cautela, adottando un giusto percorso di _deprecation_. Deprecare una firma, o parte di essa, indicando quando quella firma stessa terminerà di funzionare e quale alternative adottare, dando quindi la possibilità a chi utilizza il nostro software e quel metodo in particolare di adeguarsi, è di sicuro la strada da seguire. +Questo non significa che non sia possibile farlo ma che bisogna agire con maggiore cautela, adottando un giusto percorso di _deprecation_. Deprecare una firma, o parte di essa, indicando quando quella firma stessa terminerà di funzionare e quali alternative adottare, dando quindi la possibilità a chi utilizza il nostro software e quel metodo in particolare di adeguarsi, è di sicuro la strada da seguire. ### Estrarre nuovi metodi From a2b89b3e843aa1253959485d85ac972c87064929 Mon Sep 17 00:00:00 2001 From: Mario Ravalli <11656366+mrkrash@users.noreply.github.com> Date: Tue, 28 May 2024 22:26:18 +0200 Subject: [PATCH 18/23] Update docs/it/refactoring.md Co-authored-by: Nicola Erario --- docs/it/refactoring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 9cfe520a..21b8dcb2 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -166,5 +166,5 @@ A volte riescono a fare miracoli, ma a noi preme focalizzarci su un punto della Quanto effort occorre ad effettuare del refactoring con questi strumenti? O meglio, quanto semplificano la vita di chi sviluppa? È innegabile che sono dei validi aiuti e che sono formidabili nel farci notare parti di codice da semplificare a cui, magari, non avevamo nemmeno fatto caso. Tuttavia, affidare il refactoring all'automazione può creare delle situazioni in cui il codice modificato è così tanto, da rendere complicato il controllo da parte di chi sviluppa, tanto che potrebbe avere la tentazione di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. -C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema e a darci indici di complessità. ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. +C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema e a darci indici di complessità. Ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. Ciò nonostante, rimangono degli ottimi aiutanti: se ad essi affidiamo la correzione di tutti quegli "errori" semplici, come la tipizzazione delle variabili (nel caso di linguaggi tipizzati, ovviamente) o la riscrittura di una funzione utilizzando il pattern _Early Return_, ci ritroveremo a dover rifattorizzare del codice già scremato, lasciando la nostra mente libera di concentrarsi sul resto del lavoro da fare. From 215a71961ffb2a0aa53423cc4f6d6dd58c5d2322 Mon Sep 17 00:00:00 2001 From: Mario Ravalli <11656366+mrkrash@users.noreply.github.com> Date: Tue, 28 May 2024 22:26:51 +0200 Subject: [PATCH 19/23] Update docs/it/refactoring.md Co-authored-by: Nicola Erario --- docs/it/refactoring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 21b8dcb2..18384332 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -85,7 +85,7 @@ Cambiandone il nome, abbiamo reso più chiaro cosa farà e rendiamo più semplic Partendo dal presupposto che il codice è vivo, si possono verificare dei casi in cui un metodo riceva più informazioni del necessario. Ad esempio potremmo avere un metodo che, nella prima stesura, aveva necessità di numerose informazioni, ma, con successive riscritture, alcune di queste risultino superflue e non utilizzate. -Un altro caso può essere quello in cui un metodo necessiti di numerose informazioni che potrebbero essere accorpati in uno o più aggregati. Questo è particolarmente vero nei linguaggi tipizzati, dove potremmo verificare la possibilità di rendere detta firma più stringente, aggregando e/o restituendo tipi meno generici. +Un altro caso può essere quello in cui un metodo necessiti di numerose informazioni che potrebbero essere accorpate in uno o più aggregati. Questo è particolarmente vero nei linguaggi tipizzati, dove potremmo verificare la possibilità di rendere detta firma più stringente, aggregando e/o restituendo tipi meno generici. Prendiamo ad esempio la seguente funzione: `function updateAddress(userId: number, street: string, city: string, zipCode: string, country: string): void {}` From b9108bc26a00facda418a4e3f499518a0eea9b4b Mon Sep 17 00:00:00 2001 From: Mario Ravalli Date: Tue, 28 May 2024 22:31:29 +0200 Subject: [PATCH 20/23] Use 3 backticks instead of 1 for code snippet --- docs/it/refactoring.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 18384332..de9f621d 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -88,10 +88,17 @@ Ad esempio potremmo avere un metodo che, nella prima stesura, aveva necessità d Un altro caso può essere quello in cui un metodo necessiti di numerose informazioni che potrebbero essere accorpate in uno o più aggregati. Questo è particolarmente vero nei linguaggi tipizzati, dove potremmo verificare la possibilità di rendere detta firma più stringente, aggregando e/o restituendo tipi meno generici. Prendiamo ad esempio la seguente funzione: -`function updateAddress(userId: number, street: string, city: string, zipCode: string, country: string): void {}` + +``` +function updateAddress(userId: number, street: string, city: string, zipCode: string, country: string): void {} +``` Questa funzione potrebbe essere semplificata tramite l'introduzione di un aggregato/tipo `Address` che possa racchiudere al proprio interno tutte le informazioni necessarie: -`function updateAddress(userId: number, address: Address): void {}` + +``` +function updateAddress(userId: number, address: Address): void {} +``` + In questi casi, possiamo rimuovere le informazioni in eccesso piuttosto che sostituirle con nuovi formati, modificando di fatto la firma del metodo. C'è però da prestare particolare attenzione a questa pratica: se modificare la firma su un piccolo progetto personale è quasi privo di controindicazioni, farlo su un ambiente su cui lavorano più persone o da cui dipendono altri software su cui non abbiamo modo di intervenire, può creare non pochi problemi. Prendete il caso di una libreria utilizzata da più team: il cambiamento di una singola firma causerebbe il mancato funzionamento di tutti i software che dipendono da essa. Questo non significa che non sia possibile farlo ma che bisogna agire con maggiore cautela, adottando un giusto percorso di _deprecation_. Deprecare una firma, o parte di essa, indicando quando quella firma stessa terminerà di funzionare e quali alternative adottare, dando quindi la possibilità a chi utilizza il nostro software e quel metodo in particolare di adeguarsi, è di sicuro la strada da seguire. From dac554df68e7e1d0355627a4cd54377077615b0a Mon Sep 17 00:00:00 2001 From: Mario Ravalli <11656366+mrkrash@users.noreply.github.com> Date: Fri, 31 May 2024 11:18:32 +0200 Subject: [PATCH 21/23] Apply suggestions from code review Co-authored-by: Corrado Petrelli --- docs/it/refactoring.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index de9f621d..41e66937 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -70,7 +70,7 @@ function getNetto() { ``` Leggendone il contenuto è chiaro che ci sta tornando il totale del carrello al netto di eventuali sconti ma, senza conoscerne il contenuto, come facciamo a esserne sicuri? -Proviamo quindi a rinominarlo con qualcosa di più "parlante". +Proviamo quindi a rinominarlo con qualcosa di più espressivo. ``` function getAmountWithAppliedDiscount() { @@ -167,11 +167,11 @@ Il refactoring è un'attività contingentata che ci permette di guardare con dis ## Automazione -Esistono ovviamente diversi strumenti per automatizzare le procedure di refactoring, spesso integrati direttamente nell'IDE. Forse il più famoso è Sonarqube. +Esistono ovviamente diversi strumenti per automatizzare le procedure di refactoring, spesso integrati direttamente nell'IDE. Forse il più famoso è [Sonarqube](https://www.sonarsource.com/products/sonarqube/). Questi strumenti, basati su motori di analisi affidabili e complessi, riescono a individuare dalla banale duplicazione del codice alla mancata adozione di buone pratiche, spesso specifiche del linguaggio di programmazione adottato. -A volte riescono a fare miracoli, ma a noi preme focalizzarci su un punto della questione: l'effort. +A volte riescono a fare miracoli, ma a noi preme focalizzarci su un punto della questione: l'**effort**. Quanto effort occorre ad effettuare del refactoring con questi strumenti? O meglio, quanto semplificano la vita di chi sviluppa? È innegabile che sono dei validi aiuti e che sono formidabili nel farci notare parti di codice da semplificare a cui, magari, non avevamo nemmeno fatto caso. Tuttavia, affidare il refactoring all'automazione può creare delle situazioni in cui il codice modificato è così tanto, da rendere complicato il controllo da parte di chi sviluppa, tanto che potrebbe avere la tentazione di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. -C'è poi un altro aspetto da considerare: la specificità. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema e a darci indici di complessità. Ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. +C'è poi un altro aspetto da considerare: la **specificità**. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema e a darci indici di complessità. Ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. Ciò nonostante, rimangono degli ottimi aiutanti: se ad essi affidiamo la correzione di tutti quegli "errori" semplici, come la tipizzazione delle variabili (nel caso di linguaggi tipizzati, ovviamente) o la riscrittura di una funzione utilizzando il pattern _Early Return_, ci ritroveremo a dover rifattorizzare del codice già scremato, lasciando la nostra mente libera di concentrarsi sul resto del lavoro da fare. From f54640ec4b062083e5127375760e4f3ada735015 Mon Sep 17 00:00:00 2001 From: Mario Ravalli <11656366+mrkrash@users.noreply.github.com> Date: Thu, 27 Jun 2024 09:41:06 +0200 Subject: [PATCH 22/23] Apply suggestions from code review Approvante le correzioni suggerite Co-authored-by: Serena Sensini --- docs/it/refactoring.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index 41e66937..f3b01f73 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -34,7 +34,7 @@ Non sempre è utile effettuare refactoring. Ci sono casi in cui il codice è già perfettamente ottimizzato anche se, a una vista inesperta, potrebbe risultare di difficile lettura. Ci sono casi in cui le performance sono fondamentali e i principi SOLID non sono sempre rispettati. In questo caso, il refactoring ci porterebbe a creare dei layer aggiuntivi di codice che, sebbene possa rendere il codice più comprensibile, avrebbe un impatto negativo sulle performance. Un esempio sono le librerie che permettono le connessioni con delle basi di dati, dove magari è fondamentale la gestione della latenza. In questi casi, ma più in generale, è necessario tenere a mente che l'attività di refactoring ha tra gli obiettivi quello di rivedere il codice rendendolo più mantenibile, nonché rifattorizzabile. -Diretta conseguenza di questo obiettivo, è la sua applicazione nella pratica del TDD (Test Driven Development), dove il refactoring copre uno degli step. +Diretta conseguenza di questo obiettivo è la sua applicazione nella pratica del TDD (Test Driven Development), dove il refactoring copre uno degli step. ## Come @@ -52,9 +52,9 @@ Per farlo, potremmo iniziare con: Forse il metodo più popolare, utilizzato per mettere in pratica il TDD (Test Driven Development), dove chi sviluppa suddivide il processo di scrittura del codice in tre fasi: -- Analizza quali sono le esigenze e scrive dapprima il test, che, per ovvi motivi, fallirà (_Red_); -- Scrive il codice necessario affinché il test passi (_Green_); -- Lo migliora (_Refactoring_) +- Si analizzano quali sono le esigenze e si scrive dapprima il test, che, per ovvi motivi, fallirà (_Red_); +- Si scrive il codice necessario affinché il test passi (_Green_); +- Lo si migliora (_Refactoring_) ### Rinominare i metodi oscuri @@ -173,5 +173,5 @@ A volte riescono a fare miracoli, ma a noi preme focalizzarci su un punto della Quanto effort occorre ad effettuare del refactoring con questi strumenti? O meglio, quanto semplificano la vita di chi sviluppa? È innegabile che sono dei validi aiuti e che sono formidabili nel farci notare parti di codice da semplificare a cui, magari, non avevamo nemmeno fatto caso. Tuttavia, affidare il refactoring all'automazione può creare delle situazioni in cui il codice modificato è così tanto, da rendere complicato il controllo da parte di chi sviluppa, tanto che potrebbe avere la tentazione di prendere in blocco tutte le modifiche. Se poi siamo in presenza di una scarsa copertura di test, la frittata è fatta. -C'è poi un altro aspetto da considerare: la **specificità**. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema e a darci indici di complessità. Ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. +C'è poi un altro aspetto da considerare: la **specificità**. Gli strumenti utilizzati sono perfettamente in grado di identificare un eventuale problema e a darci indici di complessità, ma non riescono a renderci edotti del codice nel suo complesso. Senza conoscere come le varie parti del codice interagiscono nel contesto, difficilmente riusciremo a individuare eventuali errori logici o colli di bottiglia. Ciò nonostante, rimangono degli ottimi aiutanti: se ad essi affidiamo la correzione di tutti quegli "errori" semplici, come la tipizzazione delle variabili (nel caso di linguaggi tipizzati, ovviamente) o la riscrittura di una funzione utilizzando il pattern _Early Return_, ci ritroveremo a dover rifattorizzare del codice già scremato, lasciando la nostra mente libera di concentrarsi sul resto del lavoro da fare. From f47e3120c56de6ad5df77ab525d678907d961181 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Thu, 27 Jun 2024 21:38:52 +0200 Subject: [PATCH 23/23] Update docs/it/refactoring.md --- docs/it/refactoring.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/it/refactoring.md b/docs/it/refactoring.md index f3b01f73..243d8aac 100644 --- a/docs/it/refactoring.md +++ b/docs/it/refactoring.md @@ -1,4 +1,17 @@ +--- +layout: default +title: Refactor +nav_order: 14 +--- + + # Refactor +{: .no_toc } + +- TOC +{:toc} + + ## Che cos'è il refactoring