Struts lo dici a tua sorella!

Non che io abbia niente contro Struts.. niente di serio quanto meno. Però mi da in testa quando mi si dice che un certo framework “ti permette di”. Al massimo un framework “ti offre”, nel senso che se non lo usi puoi comunque ottenere quello che vuoi.
Devo ancora vedere un framework che faccia qualcosa che non posso ottenere altrimenti. Alcuni dei framework più comuni che ho usato mi hanno dimostrato il loro valore quali strumenti di incremento della produttività, ma sono sempre più convinto che nella maggior parte dei casi un framework sia visto come necessario solo perchè si è abituati a team di sviluppo che lavorano su linguaggi OO, ma che non si preoccupano minimamente del design OO.
In quel caso un framework ha una sua utilità, in quanto impone una certa architettura e, fino a un certo punto, guida la distribuzione del codice, che altrimenti sarebbe del tutto aleatoria. In effetti io ho una mia piccola teoria evoluzionistica sui perchè e i percome della salita al potere dei framework, ma non voglio perdermici qui.

Sta di fatto che certe cose sembrano proprio darmi ragione :
il mese scorso mi trovavo a discutere con un collega un’eventuale collaborazione per un progettino interno di cui aveva iniziato a occuparsi.
Non so perchè, forse quel giorno si sentiva illuminato o forse pensava di parlare con un altro, ma ha iniziato a introdurmi quello che aveva fatto come se non sapessi nulla di J2EE, così, dall’inizio della discussione. Dopo avergli assicurato in un paio di occasioni, che sì, sapevo cos’era un application server, e non avendo ottenuto null’altro che dei sorrisi accondiscendenti, ho deciso che probabilmente era stato colpito da Pierangelite acuta e sentiva quindi un bisogno forsennato di divulgare le basi della tecnica, e ho smesso di rassicurarlo, lasciandolo alla sua lezione.

“Noi, qui, usiamo Struts” dichiara a un certo punto il mio mentore (notare che siamo nello stesso ufficio da mesi, non avevamo mai lavorato assieme direttamente, ma diciamo pure che sviluppiamo sullo stesso sistema: il più classico degli Struts) e io azzardo un “Eh, già.”

“Conosci MVC?” e io : “Beh, sì, se intendi il pattern Model View Controller”.
“Intendo Struts..” e io : “Sì, che sfrutta MVC per l’appunto.. daltronde MVC è un po’ come il prezzemolo non appena si ha a che fare con interfaccie utente di qualsiasi tipo.”

Insomma, ha proseguito spiegandomi cos’era la vista e cos’era il controller (sul modello ha un po’ sorvolato, forse perchè si avvicinava la ricreazione).

La “lezione” mi ha fatto molto riflettere.

E’ un po’ come se il Model View Controller fosse questo dono di dio che ci viene offerto da Struts e che altrimenti noi non potremmo mai raggiungere.

Ora, diciamocelo : MVC è banale.. non c’è bisogno di usare Java + JSP + framework per ottenere una web application che rispetti le direttive MVC.

Visto che sono stato malato in questi giorni ho rifattorizzato una servlettina che stiamo sviluppando e che, per quanto chiara, accoppiava strettamente la business logic alla presentation. Ora, questo è male, soprattutto se il tutto è spruzzato di cablatura per passare da una vista all’altra.

In particolare la business logic era pochina, mentre l’interfaccia utente era la parte maggiore della componente e si stava insinuando un po’ troppo nel pur piccolo dominio dell’applicazione.

Per trovare i problemi di design io tendo a partire con il Single Responsibility Principle, che è un po’ il mio cavallo di battaglia. Ho guardato le varie classi che avevo usato per montare la pagina HTML, poi ho guardato i doPost e i doGet.

Alcuni dei nodi HTML che io producevo con le mie classi avevano di fatto 2 o 3 responsabilità, prendiamo ad esempio la classe UploadForm che sputa fuori questo HTML :

<form method='POST' enctype='multipart/form-data' action='/MyServlet'><input type=file name=upfile><br><input type=text name=name><br><br><input type=submit value=Press>Upload!</form>

Questa non è tutta presentazione. Lo dimostra il fatto che io nella mia doPost cerco il parametro “name” e che se ci fosse più di una post che chiama la mia servlet dovrei usare due servlets diverse o passarmi un parametro discriminante tra i due form, magari potrei aggiungere :
<input type=hidden name=formID value=1>

Quindi l’elenco degli inputs e l’indirizzo a cui mira la action sono elementi la cui definizione non riguarda questioni di presentazione, quanto questioni di controllo. Se il mio controllo decide di discriminare con handlerID io devo andare a pescare tutte le classi che generano i form e modificarle. Se sposto la mia servlet, o se la rinomino, devo modificare la action.

Questa classe non è chiusa in alcun modo.

Stesso vale per la mia doPost, che rischia di diventare un metodone pieno di “if” con la responsabilità sia di discriminare che di agire.

Prendo quindi l’azione compiuta dalla post e i controlli che dicono se e quando farla e la metto dentro a una classe UploadHandler, ci estraggo una interfaccia PostHandler che dice più o meno così:

public interface PostHandler {
boolean isInvolved(HttpServletRequest request);
void handle();
}

Faccio lo stesso per la doGet, e mi ritrovo con l’interfaccia GetHandler, identica a PostHandler.

A questo punto devo togliere una responsabilità a quelle classi che generano un HTML legato ai controlli che poi effettuano gli handlers. Per ora il posto migliore per questa responsabilità è l’handler stesso, visto che è di fatto un altro aspetto della stessa responsabilità già posseduta dagli handler : la discriminazione in base ai parametri (voglio richiamare sempre la stessa servlet, quindi non discrimino sulla action).

Aggiungo così il metodo “getInputs(String… parameters)” a PostHandler e quelle classi che devono definire un form si devono ora registrare presso un PostHandler che poi useranno per definire gli input discriminanti della loro post.
Una cosa così :

public class UploadForm extends HtmlElement implements Actor {

private PostHandler handler;

void register(PostHandler handler) {
this.handler = handler;
}

public void print(OutputStream out){
out.println(“<form method=’POST’ enctype=’multipart/form-data’ action=’/MyServlet’>”);
out.println(“<input type=file name=upfile><br>”);
out.println(“<input type=text name=name><br>”);
out.println(handler.getInputs());
out.println(“<br> <input type=submit value=Press>Upload! </form>”);
}

faccio lo stesso in GetHandler, solo che il nuovo metodo si chiama getQuery e si accoda agli hyperlink.

Ora faccio che estrarre l’interfaccia Handler che contiene i due metodi comuni a PostHandler e GetHandler (duplication is the son of the devil).

A questo punto, all’inizializzazione della servlet :
— definisco i miei handlers (control) e li inserisco in due liste : List<GetHandler> getHandlers e List<PostHandler> postHandlers.
— definisco come apparirà la pagina (presentation) componendola usando i miei elementini, quelli che implementano Actor li posso registrare presso uno degli handlers.
— inizializzo il modello, se necessario.

dentro a doGet metto questo :

for(Handler handler : getHandlers) {
if(handler.isInvolved(request)) handler.handle();
}

page.print(out);

dentro a doPost lo stesso, ma usando postHandlers, manco a dirlo.

Ora… questo non è un MVC calzato e vestito? La servlet è lunga 20 linee scarse (se metto l’inizializzazione in una factory diventano 10), posso aggiungere azioni alla servlet inserendo nuovi handlers nella lista e collegarli a un form o a un hyperlink semplicemente registrando l’elemento all’handler. E non uso nemmeno un file di configurazione!

Se avessi voluto discriminare tramite servlet, e avere uno o due (get e post) handlers per ogni servlet invece che una lista, sarei finito probabilmente in qualcosa di molto simile all’MVC di Struts.

Ne è valsa la pena? Rispetto alla vecchia servlet decisamente si, l’aggiunta di nuove funzionalità ora è del tutto modulare. E’ talmente facile che devo solo creare l’handler e solleticare la mia vena artistica provando vari layout.
Rispetto a un’ipotetica applicazione sviluppata con Struts sin dall’inizio? Forse avrei passato meno tempo a rifattorizzare ( circa il 30% del tempo di sviluppo totale ), ma questo non vale forse un’applicazione molto più leggera, non legata a un framework e che, se devo portare in giro, ha bisogno solo di sè stessa? Dipende, come al solito. Ma a me questa soluzione piace e, cosa molto importante, rispecchia esattamente i miei requisiti, non quelli ipotizzati dall’ideatore di un framework.

Si può migliorare? Penso di si, gli handlers hanno due responsabilità : la discriminazione e l’azione. Se notassi che queste due responsabilità iniziano a divergere la prima mossa sarebbe probabilmente usare lo strategy dentro gli handler e delegare una delle due responsabilità a una certa strategia.

Sun Certified Java COMPILER

Ieri ho dato il Certified Java Programmer per scaldarmi prima del Certified Java Developer, ma francamente mi ha un po’ contrariato.

Qualche settimana fa, in preparazione al test, avevo provato le venti domande di esempio che offre gentilmente mamma SUN e avevo già notato che in alcuni quesiti il criterio di valutazione era la conoscienza “meccanica” delle specifiche del linguaggio.

Qualche domanda gabola mi sta anche bene, ma l’esame vero e proprio però porta questo approccio all’estremo. Una quantità di domande comporta un’analisi minuziosa del codice proposto per trovare la gaboletta che eventualmente fa fallire la compilazione e, solo allora, si può escludere la scelta “la compilazione fallisce” e pensare effettivamente a ciò che avviene al runtime. Ora capisco perchè ti danno due ore per rispondere a sessanta quesiti a risposta chiusa. Questo tipo di paranoia da “manca forse una virgola?” rende ogni quesito estenuante e l’intero test decisamente noioso, mentre io me lo aspettavo più divertente.

Nella maggioranza dei casi poi la virgola manca davvero..

Altri quesiti invece andavano a evidenziare problematiche che forse solo un programmatore C caffeinomane considererebbe vitali. Scrivere del codice Java in cui le differenze tra ++i e i++ diventano critiche significa entrare nella mentalità “You are not supposed to understand this”. Ora, il sottoscritto è un po’ maniaco e quindi se l’è cavata egregiamente, ma addirittura tre quesiti pieni di j– e –j mi sembra divergente dall’idioma Java e dagli obiettivi di chi sviluppa usando questo linguaggio. E questo è solo un esempio.

Avessi avuto una persona davanti a me invece che a un computer penso che a molti di questi quesiti, alla domanda “cosa non va in queste venti linee?” la mia prima risposta non sarebbe stata “Lancia una IndexOutOfBoundsException”, quanto piuttosto : “Quello che non va è che questo è del pessimo codice a prescindere dalla correttezza dell’algoritmo.”

Quello che distingue un bravo programmatore non è sapere la differenza tra ++i e i++, quanto sapere scrivere del codice che risolve i problemi, invece di crearne. Ma forse non era quella la sede.

Una mezza dozzina di domande invece mi sono molto piaciute : proponevano in modo indiretto e sottile questioni effettivamente fondamentali della programmazione Java, così da assicurare che non solo si conoscano alcune caratteristiche di base del linguaggio (pass by value/reference per esempio), ma che si siano sviscerate a sufficienza per riconoscerne gli effetti anche in casi meno ovvii.

Confido che il “Developer” conterrà più domande di quest’ultimo tipo e della vera programmazione OO.

Bye bye CVS

Io e CVS abbiamo sempre mantenuto un rapporto simbiotico. In senso negativo però : io non potevo fare a meno di lui e quindi non lo potevo mandare a quel paese.
Negli ultimi due mesi invece ho provato Subversion (SVN) in tre situazioni d’uso differenti : piccolo codice in ufficio, grosso codice a casa e per un sito web.

Mai stato più contento di committare qualcosa, se vi interessa, chiedete a google perchè.

Compilare per 1.4 usando JDK 1.5

Suggerisco caldamente di tener ben presente che Eclipse è abbastanza furbo da controllare che non si usino i generics e compagnia quando si deve scrivere del codice valido per la 1.4, ma di certo non abbastanza per assicurarsi che le librerie usate siano quelle della 1.4 e non quelle della 1.5. Di certo usare le librerie della 1.5, compilare sulla 1.4, e buttare il risultato in una macchina che ha solo la 1.4 non è stata la più grande pensata del mese :)

Codice paranoico!

if((a != null && a.length > 5) && (a != null && a.indexOf(“hello”) != -1)){
…..

Non si sa mai che a diventi nullo tra un AND e l’altro!!

Comments

… o che improvvisamente la congiunzione logica cessi di essere associativa… (in altre parole si potevano togliere 2 coppie di parentesi)
Posted by matteov on 03/05/2006 11:16:45 AM

Si, ma se dovessi mettermi a considerare anche queste cose penso che riempirei il blog… Siamo ottimisti e supponiamo che le parentesi siano state inserite per raggruppare concettualmente i controlli (si prega di non ridere).
Posted by ratta on 03/05/2006 11:29:40 AM

Ah, e si prega anche di non suggerire un extract method per raggrupare i controlli.. quel codice era, come è evidente, anni luce da queste cose :) Meglio! Se no non avrei nulla da scrivere qui!
Posted by ratta on 03/05/2006 11:34:35 AM