Quando penso a cosa potrei scrivere sul blog riguardo al mondo OO e/o al software engineering in generale, mi vengono in mente non meno di cinquanta argomenti. E sono tutti equamente interessanti e importanti. Per cui nell'imbarazzo della scelta, non scrivo niente ;-)
Oggi invece voglio scrivere della pigrizia.
Si, la pigrizia.
La pigrizia è la mancanza di determinazione nel compiere un'azione di cui si riconosce l'importanza.
Il termine pigrizia deriva verosimilmente dal greco parèsis, che significa indebolimento, indolenza, rilassamento.
Secondo la catechesi della Chiesa cattolica, la perseveranza di tale atteggiamento costituisce uno dei sette peccati capitali con il nome di accidia.
Altro sinomimo di pigrizia è ignavia, un atteggiamento che Dante condanna nella Divina Commedia al punto tale che pone questa categoria di anime al di fuori di tutto, anche delle porte dell'Inferno. Appare evidente il disprezzo che Dante prova per queste anime: non li ritiene neppure degni di entrare nell'Inferno, perché nessuno li vuole, e lo stesso Poeta fa pronunciare a Virgilio la frase "Non ti curar di loro ma guarda e passa" (intendendo che la viltà di questi individui non li rende degni nemmeno di una parola).
Prima di capire cosa può centrare la pigrizia con il software engineering (o il mondo IT con qualche adattamento) vorrei citare alcune frasi da wikiquote:
È pigro l'uomo che può far di meglio. (Ralph Waldo Emerson)
La pigrizia è il rifugio degli spiriti deboli. (Philip Stanhope)
La pigrizia è madre. Ha un figlio, il furto, e una figlia, la fame. (Victor Hugo)
e alcuni proverbi che, secondo me, sono molto più taglienti e immediati:
Al cattivo zappatore, ogni zappa dà dolore.
Il caldo delle lenzuola non fa bollir la pentola.
"Io non posso" e "farò", son due pigre parole.
La pigrizia è la stupidità del corpo, e la stupidità è la pigrizia dello spirito.
In inglese pigrizia si dice lazy. Nel mondo informatico lazy significa posticipare la creazione di un oggetto, la computazione di un valore o, in generale, il calcolo di un espressione piuttosto costosa fino al primo effettivo utilizzo.
Questo permette una serie di vantaggi in termini di velocità di response nei casi in cui ci sia una gran mole di dati da computare/caricare, ma che non sono necessari tutti e subito, e permette, ad esempio, di creare strutture annidate di qualsiasi profondità senza impattare sulle performance di caricamento.
Un'esempio potrebbe essere quello di dover mostrare un elenco di Customer, ognuno dei quali ha una collezione di Order (che possono essere decine o centinaia). Se la visualizzazione degli ordini viene effettuata per un customer alla volta, allora è meglio aspettare a caricare tutti gli ordini di tutti i customer, e caricare solo quelli del customer corrente, on-demand. Analogo discorso è estendibile per altre proprietà appartenti a ciascun ordine, e via dicendo.
Questo atteggiamento si dice appunto Lazy perchè si riferisce al fatto di posticipare una cosa finchè è effettivamente necessaria. In questa accezione, l'essere lazy è lecito, consentito e consigliato.
Per completare, anche se superficialmente, il discorso sul LazyLoad, è giusto dire che vi sono diversi tipi e strategie di laziness.
LazyInitialization: si riferisce al calcolo di un campo di un oggetto, "protetto" da un valore che ne indica l'avvenuto caricamento o meno (di solito si una null per indicare che non è ancora caricato). E' la forma più semplice di LazyLoad
public class Foo {
private double? totalAmount;
public double TotalAmount{
get{
if ( totalAmount == null ){ //oppure ( !totalAmount.HasValue )
totalAmount = ComputeTotalAmount();
}
return totalAmount.GetValueOrDefault();
}
}
private double? ComputeTotalAmount(){...}
}
VirtualProxy: è un oggetto che "sembra" a tutti gli effetti l'oggetto che ci interessa (espone cioè la stessa interfaccia) ma, al primo caricamento, instanzia l'oggetto reale e delega a lui tutte le chiamate successive. Si possono trovare diversi esempi online, o in PoEEA
Ghost Object: è l'oggetto reale ma in uno stato semi-valido. Implementa il LazyInitialization per diversi campi privati e alla prima chiamata li carica tutti insieme. Sotto un certo punto di vista è come se fosse quasi un proxy si se stesso.
Sono poi possibili scenari in cui la strategia di lazy può essere sostituita a runtime per potersi adattare a diversi scenari o situazioni.
Chiuso il discorso SmartLazy/UsefulLazy (di nomi ce ne sarebbero diversi) vediamo il StupidLazy/WrongLazy
- Non scrivere i test prima, ma dopo, quando sono indispensabili:
- per "contratto": nei requisiti c'era scritto "L'applicativo deve contenere dei test funzionali" o menate varie
- per un gigantesco bug: eh si, si è spaccato il mega codice infallibile
- per un bug sottile e beffardo: ogni tanto c'è qualche errore ma in generale la cosa funziona. Frase tipica: "Non dipende dal mio codice, è impossibile"
- per disperazione: dopo ore di debugging ci si appresta a scrivere un qualche cosa che dice (in automatico!) se la cosa va oppure no
- Non scrivere la doc (aggiungere "integrata nel codice" mi sembra superfluo) prima, ma dopo 3 mesi:
- quando ormai non ci si ricorda bene alcune scelte di design
- quando alcuni punti con codice duplicato, che non si è rimosso preventivamente, diventano oscuri
- quando ci impieghi il doppio del tempo
- Non studiare nè leggere alcun libro, ma provare dicendo "tanto ci riesco":
- il "coso" che viene scritto non è modificabile
- il "coso" che viene scritto non è estendibile
- il "coso" che viene scritto è illeggibile
- il "coso" che viene scritto segue i principi di OO/incapsulamento/informationHiding in maniera naive e tutta sua
- il "coso" che viene scritto non ha eguali (o simili) in nessuna architettura mai progettata dalla notte dei tempi
- insomma, il "coso" che viene scritto va buttato
- il "coso" che è stato scritto costa almeno dieci volte tanto
- Non fare nessun prototipo con una nuova tecnologia (non nuovaInAssoluto, ma nuovaPerchèE'LaPrimaVoltaCheLaVedo) ma pagare lo scotto dopo:
- alcune limitazioni della nuova tecnologia costringono a scorciatoie e workaround assurdi
- non era tutto oro ciò che luccicava (non è una citazione perchè i verbi sono al passato ;-) )
- la nuova tecnologia non è stata capita in pieno ed è stata utilizzata al di sotto delle sue possibilità
- Non utilizzare nessuna nuova tecnologia, ma riciclare ed estendere i vecchi strumenti e pratiche:
- si è sempre fatto così, adesso mica si può rimettere tutto in discussione
- la nuova tecnologia è spesso una generazione avanti alla precedente, offrendo vantaggi indiscussi, abissali e incolmabili
- nel giro di dieci anni si è vecchi decrepiti (non significa che non si avrà lavoro, anzi, ma si sarà vecchi)
- se una tecnologia nuova è stata pensata, introdotta e utlizzata, anche se ancora acerba, un motivo ci sarà
- i luddisti sono sempre stati sconfitti
Insomma, tutto questo può essere riassunto da "non investire oggi in qualcosa che domani darà un vantaggio enorme".
Secondo me questo è uno dei peggiori atteggiamenti possibili. Spesso ci si lamenta (io per primo, sia chiaro) o ci si difende delegando la colpa a chi ci sta intorno, all'ambiente di lavoro, al capo, a Bill Gates, o al papa. Bisognerebbe cercare di divulgare il più possibile l'idea che investire oggi significa guadagnare domani; bisogna essere lungimiranti e non greedy.
Tutto questo può essere visto anche sotto l'ottica del OPC; fare una qualunque delle cose scritte negli esempi precedenti, significa rendere il proprio lavoro Close, e quindi la prima volta che serve una modifica bisogna riaprire il tutto e rimetterci le mani, non permettendo cosi al nostro prodotto di vivere a lungo.
Ecco, per me fare così vuol dire essere pigri. Dentro e fuori.