Sono un po' di giorni che penso a questo post, ma fino ad ora non ero riuscito a trovare i 30 minuti consecutivi necessari per poterlo redarre. L'intento è quello di presentare un caso reale in cui il Refactoring mi è stato di aiuto nella realizzazione di una delle ultime features di IMHO, per l'appunto il sistema di upload dei file verso l'ftp.

Quando ho iniziato il lavoro, le uniche cose che realmente avevo chiare in testa erano i seguenti presupposti:

  1. L'unico modo veramente valido per implementare la feature era di usare il protocollo FTP. Svariate ricerche in rete mi avevano confermato che l'eterogeneità dei motori di blogging lasciava poco spazio a soluzioni più sfiziose.
  2. In secondo luogo era necessario comunque lasciare aperta la possibilità, in futuro di creare soluzioni ad-hoc per ogni motore di blogging.

Armato di pazienza e di queste labili certezze, il primo passo è stato quello di cercare una libreria per l'FTP. Di certo una cosa da escludere subito era la realizzazione ex-novo di tale libreria, non perchè impossibile, ma perchè la sua implementazione avrebbe fatto lievitare inutilmente i tempi di realizzazione. La libreria trovata come sapete è la' edtFTPnet, che alcuni test comparativi mi hanno confermato essere la più affidabile.

A questo punto avrei potuto mettermi davanti ad un foglio di carta e disegnare la soluzione del problema così come sarebbe dovuta nascere, tuttavia dato il tempo scarso, e la mia ormai grande fiducia nel refactoring, ho invece aperto Visual Studio e cercato il punto migliore per innestare il nuovo codice. Alla fine la scelta è caduta sull'aggiunta di un bel metodo virtuale alla classe base degli adapter con i parametri che sembravano più adeguati e nel farne l'override in un solo engine, cosciente del fatto che il codice che avrei scritto al limite andava copiato in tutti gli altri engine.

Questa era una soluzione evidentemente temporanea, non sia mai che io cada nella trappola mortale del cut&paste, ma che mi permetteva innanzitutto di approfondire la problematica facendo funzionare il sistema velocemente. Inoltre, evidenziava una bella questione, ovvero come fare in modo, dovendo fornire a tutti gli engine il medesimo protocollo, di astrarre l'implementazione del protocollo dall'engine stesso.

Ma tutto ciò era materia per i posteri. Innanzitutto occorreva scrivere il metodo che trasferiva i file. E già questa questione apriva altri problemi. Al termine del lavoro, quando l'engine di .TEXT già pubblicava i post mi sono reso conto che lo faceva in modo logicamente errato. Infatti l'engine apriva e chiudeva la connessione ad ogni file inviato. Con un protocollo come l'FTP questo era un problema dannatamente grave, perchè l'handshake iniziale causava un overhead eccessivo. Ovviamente pensandoci bene avrei anche potuto trovarmi in futuro con protocolli diversi (si pensi ad esempio ad un webservice) che non richiedessero una apertura e chiusura della connessione. A questo punto i metodi da uno sono divenuti tre. Due responsabile di aprire e chiudere la connessione, e il terzo che trasferiva i file uno per uno. Un protocollo non connesso, semplicemente poteva lasciare vuoti i metodi Open() e Close().

Risolto questo problema era giunto il momento di estendere il funzionamento agli altri engine. Escluso a priori il cut&paste, in buona ottica oop non rimaneva che separare le responsabilità e creare una classe che si occupasse del trasferimento. E così è stato ed è nata la classe FtpPublisher. A questo punto tutti gli engine trasferivano immagini per mezzo dell'FTP. Il problema a prima vista era risolto. Ma ancora il requisito di cui al punto 2 non era del tutto soddisfatto. E' vero che è sempre possibile riscrivere un metodo, ma è anche vero che è di gran lunga meglio se non lo si fa. Inoltre, era evidente una duplicazione delle funzionalità. GLi engine così come il publisher ftp aveevano entrambi i metodi Open(), Close() e SendFile().

Quindi l'idea è stata quella di estrapolare completamente la logica di trasferimento dall'engine e semplicemente di consentire ad esso di fornire l'istanza di publisher da utilizzare per la pubblicazione. Perciò ho creato la classe astratta Publisher, e ho migrato i metodi Open(), Close() e SendFile() verso il publisher, in particolare l'ftp. A questo punto non rimaneva altro che fare in modo che l'engine creasse l'istanza di publisher e perciò ho creato una proprietà che lo restituisse a chi lo chiedeva. Tutto ciò adeguando poco a poco anche la logica che usava il publisher.

La soluzione era veramente buona. Ma ancora gli mancava qualcosa. Anche i questo caso, sostituire il publisher costringeva a ricompilare. E' stata la reflection alla fine che mi è corsa in aiuto. Modificare la proprietà degli engine per fare in modo che leggessero la classe publisher da file di configurazione è stato un gioco da ragazzi. E a questo punto ero veramente soddisfatto.

Ecco, a conclusione di questo post, vorrei rilevare come, partendo con poche certezze e armati della affilate spade dell'object-orientation e del refactoring si possa ottenere una soluzione ben congegnata, risparmiando di spremere le meningi su problemi che per ovvie ragioni all'inizio sfuggono. Ovviamente questo è il mio modo di procedere, suppongo che altri avrebbero ottenuto soluzioni differenti, ma ritengo che il succo del discorso sia davvero importante: non conta che riusciate a smontare il problema pezzo per pezzo da subito, è molto più probabile che, comportandovi come le onde del mare sulla roccia, riusciate più facilmente ad eroderlo mano a mano che esso presenta le sue parti più friabili.

powered by IMHO


Commenti (6) -

# | Davide Mauri | 30.12.2004 - 21.48

Andrea, lungi da me l'idea di negare ciò che scrivi, ma vorrei solo aggiungere un mio commento a ciò che dici. Anche sto diventando un *grande* sostenitore del refactoring ma credo ancora che un pò di design *debba* essere fatto, sopratutto nei progetti di una certa dimensione (medio / grossi). L'idea di inziare a scrivere subito senza metter giù nulla di formale mi fa inorridere un pò . Chiarisco subito. Per un progetto come IMHO che viene portato avanti da un singolo il tuo approcio è OTTIMO e da molte soddisfazioni (come si percepisce dal tuo entusiastico post)...ma sono fermamente convinto che in un progetto dove si va avanti in più di due un formalismo inziale per esser sicuri che tutti abbiano ben chiara la strada da seguire è FONDAMENTALE.

Scrivo questo non tanto per te nè per fare una critica, ma solo a beneficio di chi leggerà il post, in modo che, sopratutto se alle prime armi, non scambi il refactoring per una scorciatoia per evitare di stilare un progetto formale.

Rimango cmq conviento che il refactoring è FONDAMENTALE e, oltre tutto, è ottimo per capire davvero cosa significa programmare ad oggetti. La fregatura è che lo si apprezza solo dopo che si è provato a programmare ad oggetti per un pò e ci si è scontrati con una serie di problemi dovuti al troppo/troppo poco design.

Insomma..il refactoring è l'Inzio e la Fine. L'Alpha e l'Omega di uno sviluppatore: in questo il libro di Folwer è FANTASTICO (una grosso grazie ad AndySal per avermelo fortemente consigliato...ora anche io cerchero di diffonderlo il più possibile). Permette di capire come si programma davvero ad oggetti e, soprattutto, perchè.

In conclusione, secondo me, l'idea vincente per un progetto è: Minumum Necessary Design Upfront + Refactoring

# | Andrea Boschin | 30.12.2004 - 21.55

Hai fatto bene a precisare. Infatti non era certo mia intenzione negare la necessità di design. Il caso descritto era tutto sommato semplice e si prestava bene a lavorare nel modo descritto. Tuttavia nei casi più complessi, e soprattutto quando si lavora in team, è evidente che un po' di spremuta di meningi collaborativa ci vuole.



Il titolo del post è chiarificante. La mia intenzione era esclusivamente quella di evidenziare cosa significhi "Il design emerge" e non negarne la necessità



Grazie.

# | Luca Minudel | 30.12.2004 - 23.20

trovo le CRC card un buon strumento per fare appunto il "Minumum Necessary Design Upfront" (http://www.extremeprogramming.org/rules/crccards.html).



# | Andrea Boschin | 30.12.2004 - 23.39

Qui ne esce una confessione: ho una grande difficoltàa comprendere come funzionano le crc cards, nonostante mi sia letto molto. Questo argomento, assieme alle User Stories è per me ancora un enigma. In particolare per le user stories mi sono spesso chiesto come si fa ad essere certi che siano esaustive e come si fa a tradurle in reali funzionalità. Probabilmente un esempio pratico mi gioverebbe, ma da queste parti non so dove trovarne.

# | Luca Minudel | 31.12.2004 - 00.16

Su User Stories e CRC Marco Abis avrebbe sicuramente qualcosa di interessante da dire.



> per le user stories mi sono spesso chiesto

> come si fa ad essere certi che siano esaustive



l'analista intervistando diversi utenti si può accorge se la figura è completa o no; la sua esperienza lo aiuta, infine con la logica può verificare se quello che ha raccolto stà in piedi da solo o se invece il cerchio non è ancore chiuso.

rilasciando spesso e facendo provare agli utenti ha una ulteriore conferma che non manca qualcosa.



le crc e le user stories si applicano lavorando in gruppo, quello che va sul documento è solo il risultato finale.

ma se può aiutare, a questo link http://www.luca.minudel.it/freestaff/ingsoftdotnet.htm guarda il documento ANCOM.REQ-UTE.1001

a pag.5 e a pag.16 e ANCOM.REQ-UTE.1100 a pag.25.





# | Andrea Boschin | 31.12.2004 - 00.22

grazie. me lo studio per bene...

Aggiungi Commento