domenica 1 febbraio 2015

Dove non arriva lo spazzino

Uno degli elementi che piace di più ai giovani programmatori e a ai manager anziani riguardo a Java è il Garbage Collector: uno spazzino che arriva a liberare la memoria, che noi programmatori abbiamo allocato in modo automatico, trovando tutto ciò comodissimo.
Invito il lettore a parlare con qualsiasi sistemista che si occupi di monitorare l'occupazione di memoria della macchina e a chiedergli se anche lui (o lei) è d'accordo sulle meraviglie del Garbage Collector (GC).
Il GC è un'arma a doppio taglio, si tratta di un algoritmo complesso, che è una delle prime cause della lentezza di Java, inoltre è un invito per i programmatori per diventare pigri.
Ci sono casi infatti dove la disabitudine dei programmatori Java a occuparsi della memoria, dando fiducia completa al Garbage Collector, portano a dei memory leack.

Si possono individuare 3 casi dove il programmatore Java deve prestare attenzione, per non rendere impossibile il lavoro del GC.

1) Raggiungere l'insufficienza di memoria tramite la ritenzione non intenzionale di oggetti. Se si ritengono dei riferimenti a degli oggetti, per esempio in un vettore o in uno stack dove si desidera rimpicciolire la dimensione della struttura e non si pone a null il valore degli elementi rimasti fuori dal limite abbassato, succede che tali riferimenti impediranno al Garbage Collector di liberare la memoria degli oggetti riferiti.

2) Le cache devono liberare gli elementi più vecchi. E' comune tenere in cache dei riferimenti a degli oggetti in cache e dimenticarsi poi di togliere tali riferimenti, quando questi non sono più usati da tanto tempo. Una buona struttura per realizzare una cache in Java è il WeakHashMap. Nel caso invece dove si scelga una LinkedHashMap, esiste un metodo molto interessante: removeEldestEntry che toglie l'elemento più vecchio, magari si può realizzare un Timer o uno ScheduledThreadPoolExecutor che periodicamente lo chiama per pulire la cache degli elementi più vecchi.

3) I listener sono spesso usati per le applicazioni desktop. Richiedono molta attenzione perché i listener vanno tolti dalla lista dei listener registrati, quando non servono più, perché troppo spesso i listener rimangono e cresce il numero di riferimenti a oggetti, compromettendo l'occupazione efficiente della memoria.

Questi punti si trovano descritti sempre nell'ottimo Effective Java di Joshua Bloch.

mercoledì 28 gennaio 2015

I benefattori

Osservando le nuove offerte in campo dello sviluppo, vedo strumenti cross platform sopratutto per i cellulari.
Ho parlato con un amico, titolare di una importante software house, il quale mi diceva che stava cercando uno strumento per scrivere il codice una volta sola per Android e iOS.
Scrivere il codice una volta sola vuol dire risparmiare, avere una base unica sulla quale fare le modifiche, vuol dire tagliare i costi di produzione del proprio prodotto e raggiungere un target di clienti il più ampio possibile.

Uso Java dalla versione 1.0.1beta su OS/2 Warp, che i più giovani forse nemmeno ricordano. Dovrei sentirmi inorgoglito del fatto che oggi sempre più persone riconoscano che avevo ragione, che è importante non escludere dei clienti possibili, rispettando le loro scelte, perché il sistema operativo è parte importante del modo di lavorare di una persona e una persona lavora diverse ore al giorno...
Ricordo il dileggio di chi mi faceva notare che Microsoft era la più forte, che il mercato era saldamente nelle sue mani e gli altri erano ininfluenti. A onor del vero oggi lo scenario delle piattaforme mobili è ben diverso, molto più variegato e probabilmente gli stessi che tempo fa imparavano a usare VisualBasic e si sentivano Grandi Programmatori non si preoccuperebbero minimamente di studiare HTML, JavaScript, Java ecc... se il loro campione da seguire oggi fosse ancora il dominatore assoluto delle percentuali di installato, come negli anni '90. A loro vorrei ricordare che senza Java non ci sarebbe nemmeno C#, tentativo fallito di Microsoft di copiare una tecnologia allora migliore della loro. Oggi C# è un ottimo strumento per sviluppare su piattaforma Microsoft e gli altri mercati desktop sono ininfluenti, diverso invece è il discorso per quanto riguarda il mercato mobile.

Invece io non sono più così convinto che il cross platform sia la scelta vincente sempre.

E' più facile oggi fare cross platform rispetto a 20 anni fa: ci sono più librerie che nascondono la piattaforma e la crescente potenza dell'hardware permette di tenere degli strati di compatibilità tra l'applicativo nativo e il sistema sottostante. Penso per esempio all'ottimo Parallels su Mac OS X che permette di fare girare ad esempio  Microsoft Office per Windows senza vedere il desktop di Windows, ma di vedere le finestre Windows assieme a quelle del Mac. Penso proprio ai tempi di OS/2 quando di vedevano le finestre dei programmi per windows 3.1 assieme a quelle di OS/2, ma allora l'hardware non era così generoso come oggi e andava tremendamente piano.

20 anni di sviluppo cross platform mi hanno però insegnato che ci sono delle spine in questo mondo di rose. Le applicazioni cross platform non sfruttano mai le caratteristiche della macchina, ma soprattutto NON SI COMPORTANO SECONDO LE ABITUDINI DEGLI UTENTI.

Parlavo con un utente Windows che per le prime volte usava il fantastico The Gimp per il fotoritocco. Egli si arrabbiò perché la finestra di dialogo per aprire i file non era quella alla quale lui era abituato (The Gimp usava finestra di dialogo per Gnome) e questo particolare sminuiva tutto il progetto.

Chi ci "regala" applicazioni cross platform lo fa per LEGARCI ALLA SUA PIATTAFORMA, rendendo inutile il sistema operativo sottostante, per creare un ecosistema di applicazioni e quindi di persone, che hanno bisogno di lui. Questo spiega anche perché spesso le piattaforme cross platform impongono il loro look and feel anche quando potrebbero (e dovrebbero) appoggiarsi ai componenti del sistema sottostante. Garantire lo stesso aspetto su più piattaforme non serve tanto agli utenti, i quali tipicamente ne usano soltanto una. HTML5 mi sembra un'ottima specifica, applicata solo in parte dai produttori di piattaforme, i quali vedono positivamente la sostituzione di Flash, che è proprietario e i plugin sono pesanti, con uno standard aperto, ma l'idea che gli applicativi possano farsi senza dipendere da loro non va loro certamente a genio: quindi l'uso di uno strumento cross platform è sempre più scomodo per l'utente rispetto alle applicazioni native.

Prima di scegliere lo strumento bisogna pensare bene a cosa serve e a CHI LO USA.

NON DICO CHE BISOGNA TORNARE ALLE SOLUZIONI NATIVE in massa, dico che vedo un futuro migliore per chi sviluppa una soluzione nativa per il core dell'applicazione, che deve espandersi e crescere tramite dei generatori di codice o con dei motori che creano l'applicazione a partire da regole o parametri. Questa soluzione è oggi usata da pochi, per quando posso vedere dalla piccola finestra che ho sulla realtà, il motivo è che progettare un'applicazione è un conto, ma progettare un'architettura magari personale è tutt'altra cosa. Su questo fronte c'è ancora spazio per la piccola azienda creativa, che riscopra il valore della progettazione e dell'analisi sui dettagli che si ripropongono nei vari progetti dei quali si occupa.

La logica si può sviluppare con uno dei tanti linguaggi cross platform (Java, C#, JavaScript, anche il C++ 14 va bene) o con sistemi più sofisticati di scripting.
Anche le tanto vituperate stored procedure oggi sono piuttosto portabili e possono essere prese in considerazione e chi le sceglie merita rispetto.

Ci vuole coraggio per sviluppare la propria libreria di base. Scrivere generatori di codice o addirittura scrivere in xml dei layout che poi si applicano automaticamente ai dati da rappresentare, magari seguendo il Naked Object pattern e mettendo da parte il sopravvalutassimo MVC.

Sono queste secondo me le linee da seguire per chi nel 2015 non lavora solo su progetti altrui e vuole continuare a fare il proprio mestiere di produttore di progetti software, senza reinventare la ruota ma mantenendo la propria indipendenza e libertà.


domenica 18 gennaio 2015

Il Pinguino Talebano

  Sono un talebano, l'ho scoperto, me l'hanno detto tanto tempo fa e non ci volevo credere.
  Sono un incoerente che a volte apre il software a volte lo chiude, odia i progetti ai quali partecipa e che lo impegnano anima e corpo in una condizione monodimensionale, sottraendo tempo ed energie al resto della propria vita, come tutti i talebani insomma.

  Quindi?

  Per coerenza se sbatto la testa sul muro devo forse continuare a dare craniate affinché la gente mi applauda per la mia perseveranza, mentre io li ringrazio, con i cerotti in faccia magari?

  Stanco della classificazione e dei commenti, posso dire ora, dopo circa 20 anni di carriera nel campo del software, che la coerenza non mi interessa: mi interessano gli obiettivi e volta per volta cerco di decidere al meglio. Essere considerato un talebano perché i compromessi proposti dagli altri non risolvono il problema ora lascia il tempo che trova.

 Veniamo ora a capire perché si fanno progetti open source e dove invece l'open source non è da preferirsi.
  Ci sono diverse ragioni e motivazioni dietro alla rinuncia della segretezza: narcisismo, voglia di fare cose con gli altri, voglia di contattare altre realtà che ci possono dare lavoro, progetti scolastici, voglia di aiutare gli altri, voglia di restituire alla comunità mondiale una parte di ciò che si ha ricevuto, come se fosse un parziale risarcimenti di un debito ecc...

 Le scelte dietro alla volontà di aprire il codice VANNO RISPETTATE e ho sempre considerato dei cafoni coloro i quali hanno si facevano beffe all'inizio della comunità open, considerando a stregua di fessi quelli che rinunciavano al segreto del proprio lavoro per mettere le manette ai polsi dei propri utenti, pratica assai comune per costringere il malcapitato che ci aveva dato fiducia a continuare a pagare il bravissimo autore del proprio software.

 Ora, stando alle parole di Mr. Stallman, usare il cloud sarebbe stupido e toglierebbe libertà agli utenti. A parte il fatto che nessuno punta una pistola alla tempia dell'utente se non usa il cloud e usare il cloud è semplicemente un servizio comodo, poi ognuno fa le sue scelte.

  Ha senso aprire sempre il proprio codice, sviluppato magari a costi bassi come strategia commerciale per puntare a una lunga assistenza dopo ? Ha senso consentire ad altre persone di trarre giovamento dai nostri sforzi  e dalle nostre procedure o non è forse favorire un concorrente? E' una decisione troppo egoistica pretendere di vivere ? Oggi posso dire che a volte la chiusura è necessaria, per proteggerci da competitori senza scrupoli, però è altresì vero che sviluppare procedure ad hoc alle quali delegare la nostra sopravvivenza economica, in un mondo globalizzato, ha sempre meno senso.

  Quest'ultimo punto merita un approfondimento: 30 anni fa dove sviluppatori indipendenti e software house erano come isole staccate tra di loro, con comunicazione pressoché inesistente e delegata ai libri e alle riviste, era alta la probabilità che un diverse persone giungessero alle stesse conclusioni ma non venissero mai in contatto. La richiesta di software era in aumento costante, quindi la protezione e la chiusura erano strategie vincenti.

  Ma oggi assistiamo in ambito commerciale ciò che è stato per anni vero in ambito scientifico: le scoperte veramente originali sono pochissime, si cresce piano partendo da ciò che già esiste, le forze a disposizione delle piccole società di sviluppo sono poca cosa rispetto alla massa di software e di soluzioni testate e affidabili già disponibili.
  I grandi progetti custom sono necessari e sostenibili più che altro per le banche, le assicurazioni e la pubblica amministrazione, realtà che tipicamente rimangono proprietarie dei sorgenti dei quali commissionano lo sviluppo. La chiusura della soluzione geniale e originale venduta al cliente serve in pratica sempre meno, perché di originale non c'è proprio niente.

 Oggi l'open source è una necessità sempre più spesso, non necessariamente sempre.

 



 

 

lunedì 12 gennaio 2015

Mutatis mutandis

Ultimamente si vedono diversi articoli sulla rete che parlano di oggetti immutabili.

Addirittura classi final con metodi final che non dovrebbero essere nemmeno estensibili per evitare che una sottoclasse possa modificane il comportamento.
Indubbiamente in un contesto multi thread questa pratica risolve in partenza il problema dell'accesso concorrente, tuttavia si pongono dei problemi di ordine pratico rilevanti: per esempio se un oggetto è la radice di un albero e si desidera cambiare il nome del nodo radice, trattandosi di oggetti immutabili, bisognerebbe creare un nuovo oggetto radice e clonare tutti i nodi figli, cioè clonare l'intero albero.

Un approccio che non prevede alcun metodo set potrebbe essere devastante per lo spreco di risorse, prima di tutto per quanto riguarda l'uso della memoria, per non parlare del tempo di esecuzione.
Un altro problema degli oggetti immutabili riguarda i riferimenti alle vecchie versioni degli oggetti, che andrebbero cambiati per aggiornarli ai nuovi.

Ci può essere però una soluzione intermedia e di buon senso che risolve il problema tra oggetti mutabili e oggetti immutabili: il comportamento.

Un oggetto ha una identità, definita da uno o più proprietà, ma ha anche un comportamento, cioè ci sono dei dati che di solito sono archiviati da qualche parte e che possono cambiare senza che si cambi l'identità dell'oggetto. Per esempio prendiamo un oggetto anagrafica che ha nome, cognome indirizzo, per semplicità non ne consideriamo altri. Ora, cambiare il nome e il cognome significa cambiare l'identità della persona, quindi sono campi immutabili, il cui cambiamento è giusto che generi un nuovo oggetto anagrafica. Diverso invece è il discorso per quanto riguarda l'indirizzo, che può cambiare e che dovrebbe riflettere un  dato sul database, cioè la modifica dell'indirizzo si dovrebbe tradurre in un aggiornamento di un campo su un record dell'archivio.

In questo modo il campo indirizzo è mutabile, ma l'oggetto non muta, muta soltanto il suo "comportamento".
Il concetto di comportamento è più intuitivo se pensiamo a un oggetto che abbia il nome di un giocatore e il suo punteggio, il nome definisce l'identità e dovrebbe essere immutabile, invece il punteggio è mutabile. Dal momento che il punteggio magari è archiviato in un unico luogo (potrebbe essere una cache ma questo complicherebbe questo ragionamento, perché una cache non è altro che una copia più veloce dei dati), il riferimento degli altri oggetti all'oggetto giocatore non cambia.

Potrebbe essere questo compromesso una soluzione di buon senso. Peccato che tutto il mondo Java Enterprise non si comporti in questo modo e gli entity siano a tutti gli effetti una cache che copia spesso il modello delle tabelle sul db, essendo oggetti completamente mutabili.

La domanda che ci si può porre a questo punto è se gli oggetti del dominio applicativo possano essere degli entity o se invece non sarebbe più corretto ricorrere a oggetti che facciano da proxy verso gli entity, facendo venire i capelli bianchi a qualche manager di progetto, per i tempi di sviluppo iniziale... chissà... lascio aperto il dubbio ma credo di sì.


lunedì 5 gennaio 2015

Singleton con gli Enum

Chiudiamo questa breve carrellata sui pattern creazionali con la presentazione di una variante del Singleton Pattern.
L'intento di un pattern singleton è assicurare che una classe abbia soltanto un'istanza e che fornisca un punto globale per accedervi.

Questo implica che bisogna impedire agli altri programmatori di creare le proprie istanze, per non venire meno alla specifica di avere una sola istanza di questa classe.
Perché si debba volere una sola istanza è una scelta dell'architettura, che si può condividere o meno.
Personalmente ritengo che le singleton siano una pratica di programmazione non ottimale, soprattutto se diverse parti possono scriverci: espongono al rischio di avere dei problemi, tuttavia bisogna riconoscere alle singleton che possono tornare comode, mi viene da pensare per esempio ad una cache di dati o a un  insieme di proprietà di configurazione da accedere in sola lettura.

Le classi singleton sono spesso un problema, infatti negli ambienti managed non si possono realizzare usando semplicemente un metodo statico, che è pratica sconsigliata sia con Java Enterprise, che con Android e in generale è sconsigliabile in tutti quei casi dove ci possono essere diverse virtual machine o nodi paralleli.

La novità qui è che si può definire un costruttore privato oppure un tipo enum.

public enum Paolo {
  INSTANZA;

  public void faiQualcosa() {
  ...
  }
}

Non è una tecnica molto utilizzata, perché pochi la conoscono, però il tipo enum a un solo elemento rappresenta la soluzione migliore per implementare un singleton.

In caso di deserializzazione non si creano altre istanze e non c'è bisogno di scrivere altro codice per questo, come avviene con gli altri approcci.

Riferimenti presi da "Design Pattern Java Workbook" di Steven John Metsker ed. Eddison Wesley e Effective Java di Joshua Bloch editore Pearson Informatica.

lunedì 29 dicembre 2014

Oggetti Builder

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ì 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:

  1. Un metodo Static Factory ha un nome preciso a differenza di un costruttore, quindi comunica di più a chi lo legge.
  2. 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.
  3. 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à
  4. 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:

  1. Una sottoclasse istanziabile da un metodo static factory deve avere dei costruttori pubblici, invece non si possono chiamare costruttori privati o protected.
  2. 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