Vediamo oggi brevemente un'altra tecnica per la creazione di oggetti in Java: i Builder.
Abbiamo già visto nell'articolo precedente come in linguaggi C-like come Java manchino i nomi nei parametri passati nelle chiamate.
Questo diventa un problema nella leggibilità del codice soprattutto nei costruttori, dove oltretutto siamo obbligati a specificare soltanto un nome di metodo uguale al nome della classe.
I metodi factory presentati la volta scorsa non risolvono il problema dei nomi dei parametri e con il crescere del numero di parametri da passare, la difficoltà di comprensione e lettura del codice può solo peggiorare.
Il Builder Pattern risolve questo problema definendo una classe la quale mantiene internamente i parametri sia obbligatori che facoltativi che saranno da passare poi al costruttore vero della classe per la quale si desidera creare un'istanza.
La classe Builder deve avere dei metodi con un nome significativo per ciascun parametro da passare.
Un metodo "build" della classe builder stanzia la classe, passando i parametri valorizzati con i metodi dei quali scrivevo prima.
Si potrebbe obiettare che è sufficiente chiamare un costruttore senza parametri e poi usare dei metodi setter per passare i parametri. Purtroppo però questo presenta un altro svantaggio: usando i metodi setter non c'è un unico punto dove si può fare la validazione, cioè se diversi parametri devono concorrere per un criterio, che stabilisca la validità della creazione di un oggetto, è quasi impossibile verificare tale criterio, se i parametri sono passati con diversi metodi "set".
Il builder con il metodo "build" può concentrare il processo di validazione in un unico punto.
Inoltre JavaBeans, suggerendo di usare dei metodi setter, rende impossibile creare una classe immutabile, che oggi più che mai è importante, visto che l'hardware con il processori multi core a basso costo permette sempre di più di avere programmi con parti che girano in parallelo.
In Java l'abstract factory è realizzato dal metodo newInstance dell'oggetto Class. Purtroppo però newInstance chiama un costruttore senza parametri, con le limitazioni già discusse.
Anche per questi consigli e per vedere un esempio, si faccia riferimento all'ottimo Effective Java di Joshua Bloch.
A differenza di Bloch però, mi permetto di notare che è meglio non ricorrere a classi Builder statiche, proprio per potere usare i builder anche in ambienti multi thread, dove le parti statiche sono una fonte di problemi...
lunedì 29 dicembre 2014
lunedì 22 dicembre 2014
Creazione di oggetti
A differenza di Objective-C o di alcuni linguaggi per stored procedure dove si passano anche i nomi dei campi oltre ai loro valori, purtroppo nei linguaggi C like come Java, conta solo l'ordine e il tipo dei parametri passati.
Questo rende le chiamate dei metodi più corte, ma meno leggibili con il crescere del numero dei campi da passare.
Un altro problema è dato dal fatto che i costruttori in Java hanno il nome della classe, quindi non comunicano molto al lettore (programmatore) della propria specificità: cioè dal nome si capisce che si tratta di un costruttore, ma non si sa altro.
Per ovviare a queste limitazioni vengono in aiuto alcuni "trucchi", alcuni presi più o meno direttamente dai pattern descritti dalla Gang of Four, altri invece sono adattamenti.
Il modo più semplice per ovviare alla chiamata diretta di un costruttore è ricorrere ad un metodo Static Factory, come ad esempio:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
I vantaggi dei Metodi Static Factory sono:
Ci sono anche un paio di svantaggi, anche se a mio avviso sono poca cosa rispetto ai vantaggi:
Queste informazioni sono tratte dal libro: Effective Java di Joshua Bloch
Questo rende le chiamate dei metodi più corte, ma meno leggibili con il crescere del numero dei campi da passare.
Un altro problema è dato dal fatto che i costruttori in Java hanno il nome della classe, quindi non comunicano molto al lettore (programmatore) della propria specificità: cioè dal nome si capisce che si tratta di un costruttore, ma non si sa altro.
Per ovviare a queste limitazioni vengono in aiuto alcuni "trucchi", alcuni presi più o meno direttamente dai pattern descritti dalla Gang of Four, altri invece sono adattamenti.
Il modo più semplice per ovviare alla chiamata diretta di un costruttore è ricorrere ad un metodo Static Factory, come ad esempio:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
I vantaggi dei Metodi Static Factory sono:
- Un metodo Static Factory ha un nome preciso a differenza di un costruttore, quindi comunica di più a chi lo legge.
- Uno static Factory non deve necessariamente creare un oggetto nuovo per ogni chiamata, potrebbe infatti richiamare delle istanze pre costruite oppure chiamare un istanza con un insieme di valori particolari a seconda di quale factory pattern è richiamato.
- Uno static Factory può restituire un oggetto di un sottotipo rispetto alla classe dell'oggetto chiamato, cosa impossibile per un costruttore e questo crea una grande flessibilità
- Semplificano la creazione di istanze di tipo parametrico, come ad esempio HashMap.newInstance() che ritorna un oggetto parametrico come specificato nella parte sinistra dell'assegnazione. C'è da dire che in effetti questo vantaggio oggi è reso ininfluente dall'esistenza del diamond <>, comparso con Java 7
Ci sono anche un paio di svantaggi, anche se a mio avviso sono poca cosa rispetto ai vantaggi:
- Una sottoclasse istanziabile da un metodo static factory deve avere dei costruttori pubblici, invece non si possono chiamare costruttori privati o protected.
- JavaDoc non distingue i metodi static factory dagli altri metodi static, quindi non è sempre immediato capire se un certo metodo statico costruisce istanze o se fa altro.
Queste informazioni sono tratte dal libro: Effective Java di Joshua Bloch
Etichette:
factory,
Java,
Joshua Bloch,
metodi static factory,
metodi statici,
parametri nominali,
pattern,
pattern creazionali,
static factory
Ubicazione:
Russi RA, Italia
domenica 14 dicembre 2014
Il pesce puzza dalla testa
In un progetto è fondamentale il ruolo di chi ha l'ultima parola.
Il ruolo del capo è sempre assegnato. Nessuno ha il potere per volere divino, ma perché chi possiede il denaro comanda o più spesso delega il comando a una persona di fiducia.
La fiducia di chi possiede il denaro non è garanzia di qualità del leader. E' soltanto un atto burocratico, spesso non meritocratico.
Non c'è niente di peggio di un capo inadeguato che ha potere di veto sulle proposte degli altri membri del team e che impone una linea sbagliata.
Per linea sbagliata intendo diverse cose, non necessariamente una strategia che non può portare al risultato, quanto un atteggiamento che non tiene conto delle persone interessate al progetto, non tiene conto delle loro competenze ed esperienze, come del loro carattere.
Le persone coinvolte in un progetto sono i tecnici, ma anche e soprattutto le persone che commissionano un progetto o che lo usano.
Un progetto software è un'entità che coinvolge diverse persone con ruoli diversi e un buon capo dovrebbe tenere conto di tutti, quindi diventa importante sviluppare un nucleo di funzioni (che è l'unico obiettivo dei manager della vecchia scuola), ma anche studiare l'interfaccia utente e in generale l'usabilità dell'applicazione (Apple insegna), così come documentare per ciascun caso d'uso cosa può entrare nella procedura e cosa deve uscire, documentare i limiti e gli intervalli di validità dei dati di ingresso, come documentare cosa dovrebbero fare gli utenti nei diversi casi d'uso.
Un buon team leader deve tenere conto di tutti questi aspetti, che hanno la stessa dignità e importanza.
Un progetto ben fatto rimane soltanto un potenziale inespresso fino a quando gli utenti non diventano in grado di usarlo. Cioè rimane un sacco di soldi spesi che non portano frutto.
Ecco che il ruolo del formatore e dell'account manager assumono importanza fondamentale, la stessa importanza che hanno i tecnici realizzatori del progetto.
Fino a quando i capi progetto avranno soltanto una formazione tecnica o manageriale e nessuna esperienza nel campo della comprensione delle persone, continueremo a vedere progetti naufragare nonostante la tecnologia e la preparazione.
E' una dimostrazione di maturità, oltre che di umiltà, sapere ascoltare.
I migliori capi giudicano poco e riprendono poco, perché prima che la gente agisca, essi hanno comunicato con chiarezza cosa va fatto.
Purtroppo molto spesso una volta raggiunta una posizione alta, il capo si sente arrivato e comincia a trattare con sufficienza i membri del team o i clienti, come se questi fossero tutti meno preparati o con capacità cognitive inferiori. Il risultato è spesso una serie di incomprensioni e di acredini.
La cosa che tutt'oggi mi sorprende è come chi investe soldi nel progetto, spesso non ponga obiettivi intermedi o almeno criteri di valutazione per capire se chi comanda, ha le qualità tecniche, ma soprattutto umane per dirigere un lavoro nel modo migliore e si aspetti la fine del progetto per giudicare tutto il team, come se fosse un giorno del Giudizio Universale, dove chi paga è un dio cieco e sordo, che si è svegliato dal torpore, per capire all'ultimo momento che chi comandava, non era adatto a quel ruolo.
Il ruolo del capo è sempre assegnato. Nessuno ha il potere per volere divino, ma perché chi possiede il denaro comanda o più spesso delega il comando a una persona di fiducia.
La fiducia di chi possiede il denaro non è garanzia di qualità del leader. E' soltanto un atto burocratico, spesso non meritocratico.
Non c'è niente di peggio di un capo inadeguato che ha potere di veto sulle proposte degli altri membri del team e che impone una linea sbagliata.
Per linea sbagliata intendo diverse cose, non necessariamente una strategia che non può portare al risultato, quanto un atteggiamento che non tiene conto delle persone interessate al progetto, non tiene conto delle loro competenze ed esperienze, come del loro carattere.
Le persone coinvolte in un progetto sono i tecnici, ma anche e soprattutto le persone che commissionano un progetto o che lo usano.
Un progetto software è un'entità che coinvolge diverse persone con ruoli diversi e un buon capo dovrebbe tenere conto di tutti, quindi diventa importante sviluppare un nucleo di funzioni (che è l'unico obiettivo dei manager della vecchia scuola), ma anche studiare l'interfaccia utente e in generale l'usabilità dell'applicazione (Apple insegna), così come documentare per ciascun caso d'uso cosa può entrare nella procedura e cosa deve uscire, documentare i limiti e gli intervalli di validità dei dati di ingresso, come documentare cosa dovrebbero fare gli utenti nei diversi casi d'uso.
Un buon team leader deve tenere conto di tutti questi aspetti, che hanno la stessa dignità e importanza.
Un progetto ben fatto rimane soltanto un potenziale inespresso fino a quando gli utenti non diventano in grado di usarlo. Cioè rimane un sacco di soldi spesi che non portano frutto.
Ecco che il ruolo del formatore e dell'account manager assumono importanza fondamentale, la stessa importanza che hanno i tecnici realizzatori del progetto.
Fino a quando i capi progetto avranno soltanto una formazione tecnica o manageriale e nessuna esperienza nel campo della comprensione delle persone, continueremo a vedere progetti naufragare nonostante la tecnologia e la preparazione.
E' una dimostrazione di maturità, oltre che di umiltà, sapere ascoltare.
I migliori capi giudicano poco e riprendono poco, perché prima che la gente agisca, essi hanno comunicato con chiarezza cosa va fatto.
Purtroppo molto spesso una volta raggiunta una posizione alta, il capo si sente arrivato e comincia a trattare con sufficienza i membri del team o i clienti, come se questi fossero tutti meno preparati o con capacità cognitive inferiori. Il risultato è spesso una serie di incomprensioni e di acredini.
La cosa che tutt'oggi mi sorprende è come chi investe soldi nel progetto, spesso non ponga obiettivi intermedi o almeno criteri di valutazione per capire se chi comanda, ha le qualità tecniche, ma soprattutto umane per dirigere un lavoro nel modo migliore e si aspetti la fine del progetto per giudicare tutto il team, come se fosse un giorno del Giudizio Universale, dove chi paga è un dio cieco e sordo, che si è svegliato dal torpore, per capire all'ultimo momento che chi comandava, non era adatto a quel ruolo.
lunedì 8 dicembre 2014
Oggetti immutabili
Anni fa, secoli in termini informatici, esisteva il BASIC.
Il BASIC aveva un comando assai comodo: il GOTO che faceva saltare l'esecuzione del programma in un altro punto. Chiunque avesse studiato l'Assembly era abituato alle istruzione di Jump e non si vedeva niente di strano a fare salti con il GOTO.
L'abuso del GOTO portava a programmi per i quali era quasi impossibile seguire chiaramente il flusso di esecuzione del codice e si coniò un termine per quello stile di programmazione : "Spaghetti Code" per via del groviglio che assumeva il flusso delle istruzioni, che in condizioni ideali, dovrebbe essere il più lineare possibile, per facilitare la leggibilità e la comprensione del programma.
Divenne comunemente accettato nella pratica della programmazione bandire il GOTO e "condannare" chi ne faceva uso come cattivo programmatore.
Più volte nella storia della programmazione si è considerata cattiva pratica qualcosa che fino a prima sembrava la cosa più normale del mondo.
Sono stati oggetto di ostracismo le stored procedure, la programmazione procedurale, la programmazione non cross platform ecc...
Oggi la diffusione sempre maggiore di macchine con ottime capacità di lavoro in parallelo e a basso costo, ha costretto a riconsiderare alcune pratiche di programmazione, che creano problemi in questi nuovi scenari.
Poter cambiare i valori delle proprietà di un oggetto in un contesto multithread, per esempio, è pericoloso perché ci espone al rischio che ci sia un accesso concorrente di più thread alla stessa risorsa, con blocchi o risultati difficilmente prevedibili.
Una delle strategie più recenti per difendersi da questi problemi, è semplicemente rendere gli oggetti immutabili, cioè non si deve permettere la modifica di un oggetto dopo la sua creazione e bisogna ricorrere alla creazione di un oggetto nuovo con i nuovi valori, che andrà a sostituire il vecchio.
Di sicuro non è un approccio che favorisce le prestazioni, però in effetti bisogna ammettere che evitare i rischi del multithreading è allettante.
Detto questo, ci sono casi nei quali un oggetto immutabile è semplicemente impossibile, per esempio una maschera dove i bottoni sono abilitati o disabilitati a seconda dello stato dell'applicazione, mi sembra la dimostrazione che in pratica un approccio così totalizzante, come evitare SEMPRE le classi mutabili, non sia possibile.
Un altro possibile approccio è quello usato dagli application server Java, dove la specifica proibisce ai programmatori delle web app di usare i thread, perché l'application server fornisce gli strumenti per far girare il codice in parallelo, senza ricorrere direttamente ai thread.
E' senza dubbio un'altra strategia difensiva, purtroppo però non è pensabile che ci sia sempre un application server sotto alla nostra applicazione, quindi non è una ricetta universale.
Il BASIC aveva un comando assai comodo: il GOTO che faceva saltare l'esecuzione del programma in un altro punto. Chiunque avesse studiato l'Assembly era abituato alle istruzione di Jump e non si vedeva niente di strano a fare salti con il GOTO.
L'abuso del GOTO portava a programmi per i quali era quasi impossibile seguire chiaramente il flusso di esecuzione del codice e si coniò un termine per quello stile di programmazione : "Spaghetti Code" per via del groviglio che assumeva il flusso delle istruzioni, che in condizioni ideali, dovrebbe essere il più lineare possibile, per facilitare la leggibilità e la comprensione del programma.
Divenne comunemente accettato nella pratica della programmazione bandire il GOTO e "condannare" chi ne faceva uso come cattivo programmatore.
Più volte nella storia della programmazione si è considerata cattiva pratica qualcosa che fino a prima sembrava la cosa più normale del mondo.
Sono stati oggetto di ostracismo le stored procedure, la programmazione procedurale, la programmazione non cross platform ecc...
Oggi la diffusione sempre maggiore di macchine con ottime capacità di lavoro in parallelo e a basso costo, ha costretto a riconsiderare alcune pratiche di programmazione, che creano problemi in questi nuovi scenari.
Poter cambiare i valori delle proprietà di un oggetto in un contesto multithread, per esempio, è pericoloso perché ci espone al rischio che ci sia un accesso concorrente di più thread alla stessa risorsa, con blocchi o risultati difficilmente prevedibili.
Una delle strategie più recenti per difendersi da questi problemi, è semplicemente rendere gli oggetti immutabili, cioè non si deve permettere la modifica di un oggetto dopo la sua creazione e bisogna ricorrere alla creazione di un oggetto nuovo con i nuovi valori, che andrà a sostituire il vecchio.
Di sicuro non è un approccio che favorisce le prestazioni, però in effetti bisogna ammettere che evitare i rischi del multithreading è allettante.
Detto questo, ci sono casi nei quali un oggetto immutabile è semplicemente impossibile, per esempio una maschera dove i bottoni sono abilitati o disabilitati a seconda dello stato dell'applicazione, mi sembra la dimostrazione che in pratica un approccio così totalizzante, come evitare SEMPRE le classi mutabili, non sia possibile.
Un altro possibile approccio è quello usato dagli application server Java, dove la specifica proibisce ai programmatori delle web app di usare i thread, perché l'application server fornisce gli strumenti per far girare il codice in parallelo, senza ricorrere direttamente ai thread.
E' senza dubbio un'altra strategia difensiva, purtroppo però non è pensabile che ci sia sempre un application server sotto alla nostra applicazione, quindi non è una ricetta universale.
Iscriviti a:
Post (Atom)