27 ottobre 2014

Il cliente (NON) ha sempre ragione!

Dovete sapere che sebbene mi concentro sul mio lavoro, spesso e volentieri tendo a captare i dialoghi di lavoro altrui... che potrebbe sembrare una cosa del tipo "Non ti fai i caxxi tuoi" ma è discutibile.

In ogni caso è proprio la mia curiosità che ha salvato il NuovoArrivato dal dover debuggare tutta l'applicazione e costringere il nostro SistemistaTuttoFare a spostare db a destra e a manca.

NuovoArrivato: avrei bisogno di lavorare con il db X avendo l'applicazione DODO in locale.
SistemistaTuttoFare: ok, capisco, ma a che ti serve fare tutto ciò?
NuovoArrivato: devo testare DODO partendo dai dati caricati per capire perché gli Storditi (di questo gruppo comandato dal GrandeStordito ve ne parlerò più in là) non riescono a vedere l'xls prodotto dal backend di DODO. Excel gli dice che è tutto sminchiato.

Sentendo queste parole il mio onesto cervello si mette in moto e decide di mettersi in mezzo alla discussione in aiuto, sebbene potrei pure fottermene considerando che è la mia ultima settimana.

Io: mmm scusami NuovoArrivato potresti spiegarmi meglio il problema che devi risolvere?
NuovoArrivato: si certo dunque bla bla bla xls bla bla bla Excel bla bla bla...
Io: No caxxo! Ho capito! Se stanno usando il frontend vecchio con il backend nuovo allora è quel maledetto bug!

Quel maledetto bug è ovviamente dovuto al fix di un altro bug... che non andava considerato tale!


Una breve spiegazione: molto tempo fa DODO backend produceva dei report che dovevano essere visualizzati su DODO frontend. Tra i tipi possibili di report prodotti c'erano dei file testuali csv creati però erroneamente con estensione .xls. Con Excel è possibile leggere questo tipo di file senza problemi, solo che se tali file hanno in realtà una estensione errata Excel ti avvisa prima di aprire il file che l'estensione è sbagliata, che il contenuto potrebbe essere corrotto, che ci potrebbe essere uno Tsunami se per puro caso apri il file ecc... insomma un semplice warning forse un po' esagerato dovuto ad un controllo sul formato del file. Dopo il warning il file si apre senza problemi.

Peccato che al cliente questo non piaccia e inviano un ticket per "risolvere il problema". Ora dal mio punto di vista le soluzioni possibili erano solo due:

  1. Rigettare il ticket, considerando il fatto che DODO produce dei file ed è responsabile del formato dello stesso, ma non può esserlo sul client usato per aprire tale file. Per cui si fot***sero e si lamentassero con la Microsoft o cambiassero programma per aprire in realtà quello che è un file testuale csv.
  2. Modificare il backend per creare il file con estensione .csv (come si doveva fare dal principio) e gestire tale modifica sul frontend.
Io sarei stato molto predisposto per l'opzione 1 semplicemente perché NON POSSIAMO STARE APPRESSO A TUTTE LE RICHIESTE DEL CAXXO DEL CLIENTE, soprattutto se quest'ultimo ha un'approccio all'IT come se fosse Topo Gigio. Noi sviluppiamo e manuteniamo DODO e rendiamo compatibile il suo frontend a quella fetenzia di browser partorita dalla Microsoft, ma per il resto ci dovremmo fermare qui.

D'altro canto il cliente paga per cui... se proprio fossi stato costretto, avrei adottato l'opzione 2.

Il problema fu che non mi occupai io del problema, ma il tutto fu assegnato al fantastico duo MasterBugProducer e SeniorPigro che riuscirono a risolvere il problema modificando solo il frontend di DODO con un fantastico porkworkaround. Al tempo ero impegnato in altro e non avevo alcuna voglia di sapere come avessero "risolto" il problema.

Poco tempo dopo il backend di DODO venne rifatto completamente e fu in grado di produrre dei veri fogli excel, niente di testuale. Durante lo stesso periodo il cliente aprì un ticket riguardo l'illeggibilità dei report xls e mi fu assegnato codesto ticket.

Ci misi parecchio tempo a debuggare poiché partì ovviamente dal monte, cioè dal backend di DODO che produceva direttamente il report xls senza trovare alcuna magagna. Per pura curiosità allora andai ad aprire la action Struts con il quale si permetteva all'utonto di scaricare i report selezionati dalla GUI e scoprì qualcosa che mai avrei voluto leggere:


if (format.getName().equals("xls")) {
    InputStream is = file.getInputStream();
    MagicNumber mn = MagicNumber.parse(is);
    is.close();
    String encoding = null;
    if (mn == null) {
       encoding = "ISO-8859-1";
    } else {
       encoding = ((TextMagicNumber) mn).getCharacterEncoding();
         }
   ...
    new InputStreamReader(bc.getInputStream(), encoding)).writeTo(new OutputStreamWriter(lengthOut,"UnicodeLittle"));
}


A parte la gestione fatta a caxxo sugli stream, questo schifo consiste nel fix sul warning di Excel. Non si sa come ma SeniorPigro riuscì a scoprire che modificando il character encoding di un file csv con estensione .xls in UTF16-LE (UnicodeLittle sta per "Unicode Little Endian"), il warning su Excel spariva. Quella gran coppia di intelligentoni ebbe così la grande idea di convertire qualsiasi file .xls proveniente dal backend in UTF16-LE, cercando di scoprire l'encoding originario con una cagata di classe MagicNumber che non mappa nemmeno 1/3 di tutti i character encoding esistenti.

Che succede se provate a leggere il contenuto di un file binario con un InputStreamReader tramite un certo character encoding e a scriverlo con OutputStreamWriter con un altro character encoding? 

Succede che sputtanate tutto il file!

Ne parlo quindi con il mio responsabile e decidiamo stavolta in maniera intelligente di eliminare questo accrocchio (che non ho il coraggio di chiamare fix) e che eventuali future lamentele su messaggi di warning di Excel verranno cestinati e nel caso peggiore gestiti direttamente a monte sul backend.

Peccato che NuovoArrivato stesse lavorando su un branch SVN in cui il bug di cui sopra non era ancora stato fixato.

In conclusione per rincorrere le pretese idiote del cliente, grazie anche all'incompetenza di una coppia di programmatori è stato introdotto un bug che si è diffuso come un virus in tutte le installazioni di DODO.

23 ottobre 2014

Pensa. Prima di committare, PENSA!

Sarò fissato io... ma di solito quando mi trovo di fronte ad un bug da fixare effettuo i seguenti step:

  1. Analizzo il bug. Se non lo capisco chiedo spiegazione a chi l'ha aperto oppure a chi detiene la conoscenza del contesto.
  2. Provo a replicare il bug (non è questione di non fidarsi ma chi apre il bug non conoscendo il codice non può fornire un quadro completo e quindi può solo ipotizzare che si verifichi secondo alcune condizioni evidenti a GUI o a configurazione).
  3. Analizzo il codice per scovare il bug (nei casi peggiori potrei far uso di debugging pesante).
  4. Analizzo le possibili alternative per fixare il bug (un fix anche semplice potrebbe causare infinite regressioni, soprattutto in una situazione da spaghetti code).
  5. Fixo il bug.
  6. TESTO il fix.
  7. Committo il fix sul repository dei sorgenti e dichiaro fixato il bug con annesso commento del come, del quando e del perché.
Nei casi migliori però tutto il processo si potrebbe fermare al punto 2, poiché può capitare che vengano aperti bug che in realtà non lo sono, vuoi per una svista o vuoi perché il comportamento del programma deve essere proprio in quel modo, come dichiarato da specifiche. Della serie "It's not a bug, it's a feature!".

IMMAGINATEVI che nel mio team ci sia un altro sviluppatore che d'ora in poi chiameremo MasterBugProducer e che ha sempre fatto onore a questo soprannome e che sicuramente non ha mai avuto un approccio simile a quello spiegato sopra. 
IMMAGINATEVI un particolare use-case in cui bisogna interagire con una combo presente in una pagina JSP, la cui visibilità (della combo) dipende da alcuni fattori.
IMMAGINATEVI che inizialmente la visibilità di questa combo dipendeva da un controllo hard-coded e che io abbia migliorato la situazione rendendo la visibilità dello stesso dipendente da alcune configurazioni su DB, rispettando le specifiche.
IMMAGINATEVI che a MasterBugProducer venga assegnato un bug che dice "La combo non si vede mai" ma in realtà non è così perché chi ha segnalato il bug si è fermato alla pagina prima rispetto a quella dove la combo è realmente presente, senza andare avanti con lo use-case.
IMMAGINATEVI che MasterBugProducer invece di analizzare il fatto e/o provare a replicare il falso bug, abbia committato un qualcosa che sembra un fix ma non è: non solo avrebbe sovrascritto completamente la mia modifica sulla visibilità di COMBOX reintroducendo il controllo hard-coded, ma lo avrebbe anche scritto MALE producendo una regressione!
IMMAGINATEVI che MasterBugProducer non abbia mai fatto un test!

Ovviamente il cliente se ne accorge, notifica il nuovo bug prodotto dalla risoluzione di un falso bug, me lo trovo io tra le mani, scopro tutto il fattaccio, tiro fuori il mio manganello picchia-sviluppatori-che-dovrebbero-zappare-la-terra, cerco MasterBugProducer scoprendo tristemente che oggi è in ferie.

Rassegnato da ciò fixo il bug (che consiste nel buttare nel cesso tutte le modifiche fatte da MasterBugProducer) e fiducioso del fatto che tra una settimana me ne vado via, scrivo codesto commento al commit:

Reverted fix by cocked head MasterBugProducer because he doesn't think before commit (PLEASE the next time, if you don't understand the code, can you ASK before OVERWRITE A WORKING FIX?!?!?)

Per quanto faccia cagare il mio inglese, penso di farmi capire molto bene.

20 ottobre 2014

Reverse Millennium bug

Ebbene si... il Millennium bug esiste ed è esistito (anche se non ha prodotto eventi catastrofici come ci hanno fatto credere ne I Simpson) ma non solo! Esiste pure la sua variante che personalmente ho scoperto in questa fetenzia di progetto sul quale ho lavorato per circa 3 anni!

Dovete sapere che MultinazionaleCazzara ha un modo di fare un po' particolare: tende ad acquistare progetti di software inizialmente creati da piccole aziende, per poi gestirli in proprio e rivendere il prodotto a clienti più o meno grossi. Si tratta di programmi/portali/qualisasialtracosaeseguibilesuunserver che difficilmente potrebbero essere venduti senza un grande nome dietro, poiché i ClientiPecoroni che MC riesce a contattare valutano lo stesso solo in base al marchio che ci sta sopra. Poco importa se il prodotto in questione è una ciofeca progettata e sviluppata a canem cazzum come dicevano gli antichi Romani: basta una banalissima demo per far impressionare MC e convincerla a poterci fare soldoni, tralasciando completamente un'analisi della parte tecnica.

Questo prodotto, a cui è stato dato il nome di un animale istinto per cui per comodità lo chiamerò DODO, ha più di 10 anni ed ha praticamente visto tutte le possibili tecnologie e framework Java esistenti. E quando dico "visto" intendo che nello stesso progetto (composto però da più moduli) sono stati usati proprio TUTTI i framework e standard di tendenza: si è partito con la tripletta Struts+Spring+Hibernate, con supporto di un gran numero di framework JS (usati tutti pure sulla stessa pagina) tra cui JQuery, Prototype, DWR e Dojo per arrivare a roba un po' più recente come JPA, CDI, EJB3 ed altro. Alcuni moduli per fortuna sono stati rifatti da zero, altri invece non hanno avuto ancora modo di ricevere l'eutanasia e sono diventati praticamente l'esempio migliore di quello che si definisce vero software legacy, roba per cui il termine "spaghetti code" è poco esplicativo.

Tanto per mettere il dito nella piaga, la grande idea di MC nell'acquistare DODO fu anche quella di non usare un team locale di sviluppatori per il mantenimento e lo sviluppo di nuove funzionalità ma di usare invece un team di Cinesi di MC, poiché costano molto di meno.

Ebbene si... pure nel magico mondo del bodyrentalconsulenza dobbiamo avere paura del made in china. Ma ovviamente come lo è per i prodotti fisici fatti dai Cinesi, anche quelli software fanno cagare e si rompono solo dopo un paio di giorni di utilizzo.

Ed è proprio uno di questi Cinesi dal nome impronunciabile che è stato in grado di creare un Reverse Millenium bug.

Come ha fatto? Semplice... in DODO c'è la necessità di estrarre da un oggetto di tipo java.util.Date una stringa nel formato yyDDD, ovvero una stringa contenente le due cifre dell'anno e le tre cifre per indicare il giorno nell'anno.

Per esempio il 20 ottobre del 2014 diventerebbe 14293.

Il Cinese in questione che chiamerò Sohunasegahio non conosce la teoria del "mai reinventare la ruota" (teoria molto importante di cui cercherò di parlare più approfonditamente più in là) ed è convinto che non si possa implementare una funzionalità del genere in queste tre righe di codice:

Date date = new Date();
SimpleDateFormatter formatter = new SimpleDateFormatter("yyDDD");
String code = formatter.parse(date);

Sohunasegahio ha pensato invece di implementare un algoritmo di una trentina di righe (che purtroppo non posso incollarvi) che fa dei calcoli astrusi con divisoni, multipli, sottomultipli e cazzi e mazzi chiamando addirittura metodi a cascata.

In ogni caso l'algoritmo implementato da Sohunasegahio funziona perfettamente... solo per le date il cui anno è compreso tra il 2000 e il 2100. Anche basandosi sulla speranza che DODO non vedrà mai il finire di questo secolo, rimangono purtroppo le date comprese nel 900, che producono dei codici lunghi dalle 6 alle 8 cifre che ovviamente non corrispondono al voluto.

La fortuna di Sohunasegahio però sta nel fatto che tale algoritmo, per circostanze che non sto a spiegarvi, elaborerà sempre e comunque date non troppo passate rispetto alla data odierna, per cui non c'è mai stata e probabilmente né ci sarà mai la possibilità per cui si scoprirà effettivamente questo bug.

L'algoritmo non l'ho toccato minimamente poiché è diventato il punto di riferimento sulla mia tesi: Un team di sviluppatori di Indiani o Cinesi potrebbe pure risultare conveniente in termini di costi, ma se tu paghi in noccioline non stupirti poi se a lavorare sul tuo progetto ci stanno delle scimmie ammaestrate che farebbero meno danni a lavorare nelle risaie.


16 ottobre 2014

La patata bollente

A meno di eventuali incidenti che incontro lungo la strada, di gente che la patente deve averla presa al CEPU non conoscendo nozioni molto semplici quali "l'uso della freccia per il cambio di corsia" oppure "distanza di sicurezza", di solito a lavoro arrivo molto calmo e sereno.

Poi purtroppo, poiché sarei stato assunto in qualità di programmatore, sono obbligato ad aprire il codice e, per colpa del mio animo molto sensibile ed emotivo, mi incupisco profondamente quando leggo cose del genere:

void metodogenerico(Tipo argomentogenerico) throws Exception {
...
}

Se consideriamo poi che una firma di questo tipo è presente in TUTTO il progetto, allora inizio ad incazzarmi come una iena!

Quel maledetto throws Exception è uno dei peggiori antipattern usati da chi non ha mai capito come funzioni la gestione delle eccezioni in un qualsiasi linguaggio OOP e che secondo me dovrebbe provare un altro mestiere... tipo andare a zappare la terra che così danni non ne crea.

La cosa peggiore di questo antipattern non è solo l'utilizzo in sé ma il danno che ne consegue poi su tutti i metodi chiamanti. Eh si perché se il primo programmatore imbecille scrive una ciofeca del genere, costringe poi tutti gli altri che lavorano sui chiamanti a fare la stessa cosa. In realtà se il metodo incriminato fosse uno solo, basterebbe anche un solo programmatore serio a correggere immediatamente l'errore prima del diffondersi il virus. Peccato che questo non accade, vuoi per pigrizia oppure per la stessa imbecillità che ha portato il primo a scrivere la ciofeca. 

Si arriva quindi al giorno in cui su una certa Action struts io debba chiamare un metodo che rilancia Exception, che a sua volta chiama un metodo che rilancia Exception, che a sua volta ancora... eccetera eccetera, fino ad arrivare in Cina con la stessa metodologia (la lunghezza dello stacktrace è talmente lungo che ricopre sicuramente una distanza simile a Roma-Pechino in linea aerea) , quando però devo creare una logica di gestione degli errori.

PECCATO che durante tutto il flusso fino al backend, potrebbero avvenire eccezioni GESTITE  di varia natura, dalla chiamata fallita ad un webservice fino ad un semplice controllo di formato di un parametro.

PECCATO che io dovrei mettere la richiesta in errore solo per alcuni casi specifici mentre per altri no.

PECCATO che apparentemente non ci sia differenza tra una connessione down del webservice o il formato sbagliato di un parametro, poiché in tutti e due i casi si lancia la stessa checked exception ma con message diverso

PECCATO che non posso rifattorizzare un cazzo perché questo significherebbe perdere più tempo rispetto al dover rifare tutto il modulo d'accapo.

PECCATO che nessuno si sia mai accorto di questo problema di cattivo design, continuando imperterrito a scrivere i propri metodi con la ciofeca descritta sopra

PECCATO che devo essere sempre io l'unico idiota ad incazzarmi per una cosa del genere quando per tutto il resto del mondo va bene!

La ciliegina sulla torta è che su questo progetto la gestione di messaggi di errori provenienti dal backend viene fatto nel seguente modo

private void validateParametro(Tipo parametro, List<String> messaggiDiErrore) {
...
}

private void metodoDiBusiness(vari parametri, List<String> messaggiDiErrore) {
...
}

validateParametro(param1, messaggiDiErrore);
if(!messaggiDiErrore.isEmpty) {
 gestisci errore
 interrompi esecuzione action
}
validateParametro(param2, messaggiDiErrore);
if(!messaggiDiErrore.isEmpty) {
 gestisci errore
 interrompi esecuzione action
}
metododiBusiness(vari parametri, messaggiDiErrore);
if(!messaggiDiErrore.isEmpty) {
 gestisci errore
 interrompi esecuzione action
}

Ovviamente chi ha ideato una cosa del genere non si è minimamente immaginato che una Exception è anche un oggetto istanziato da una classe! Quindi magari poteva pure creare una checked exception, con all'interno il suddetto array di messaggi ed usare semplicemente un bel try catch! Ma no... meglio ridondare il codice ed evitare di usare sapientemente le eccezioni, anche se dovresti essere considerato un Senior Java Consultant.

Rilanciamo sempre al chiamante la patata bollente, tanto prima o poi il coglione che lo dovrà cucinare ci sarà.

Cioè io.


14 ottobre 2014

Hello World!

Era il lontano 2010 quando mi trasferì a Roma per il mio primo lavoro.

Nel marzo dello stesso anno avevo finalmente ottenuto quel dannato pezzo di carta dalla mia università terrona ("ottenuto" non proprio letteralmente, visto che ancora oggi dopo 4 anni, nonostante abbia pagato la marca da bollo, non sono mai andato a prendere la pergamena di laurea... troppo antipigro andarla a prendere in questo momento) ed ero tanto desideroso di lavorare per non essere etichettato più come un bamboccione mantenuto da mamma e papà.

A pensarci ora mi viene proprio da ridere... avete presente quel momento della vostra vita in cui avete scoperto che Babbo Natale non esiste? Moltiplicate quella sensazione per 100.

Figuriamoci se all'università i professori avessero mai avuto il coraggio di parlarci del flagello che affligge il mondo dell'IT da molto prima della mia nascita lavorativa,

Una specie di Voldem... colui-che-non-deve-essere-nominato.

LA CONSULENZA INFORMATICA!

(anche se andrebbe chiamato con il suo vero nome... il bodyrental!)


HR: Sig. S, il suo profilo è ottimo e lei potrebbe essere la persona che cerchiamo per il nostro stage di inserimento nel nostro quadro aziendale.
S: Perfetto, sono molto felice di questo.
HR: Ovviamente come lei sicuramente sa noi siamo una società di consulenza informatica e noi stiamo appunto cercando qualcuno da istruire che possa poi diventare un consulente competente in ambito Java presso i nostri clienti. Lei sa come funziona la consulenza, vero?
S: si certo ovviamente (mentendo spudoratamente).

Beata ignoranza... solo dopo 4 mesi di stage su Java e affini e la sudata assunzione (di questo mi posso ritenere parecchio fortunato) mi resi conto del danno fatto e di quanto sembrava assurdo l'idea di "consulenza" nel mondo dell'informatica.

Andare dai clienti? A fare che? Non lavorerò qua? Non vi serve uno sviluppatore qui? E dove vado? E quanto è lontano? Non dovrò mica mettere giacca e cravatta (bleah!) vero? E se gli sono antipatico? E se mi odiassero? Oddio non occupo molto spazio, potrei stare benissimo in quell'angoletto che la donna delle pulizie non pulisce mai e non disturberei nessuno! Suvvia non mandatemi lì, vi prego! Ok va bene vado lì ma vi farete sentire vero? Mi chiamerete periodicamente per sapere come va vero? VERO?!?!?!?


Ed eccomi qui, 3 anni dopo, sempre presso lo stesso cliente, una nota multinazionale che d'ora in poi chiamerò MultinazionaleCazzara o MC, senza essere stato minimamente cagato dalla mia azienda, che chiamerò d'ora in poi MarkettariSoftware o MS, se non per i seguenti motivi:


  1. MS: vedi che ti sei scordato di compilare le ore del rapportino che devi presentare mensilmente, rapportino che non serve ad altro che a capire se sei ancora vivo considerando che devi compilare tutti i giorni allo stesso modo (non sto scherzando, da quando lavoro in MC ho compilato stesse ore 9-18, stesso progetto, stessa sede, stessi codici, per 3 anni!!!)
  2. MS: i buoni pasto sono nella nostra sede, che sono ovviamente lontani dalla sede di MC dove tu lavori e non si trova manco per strada, ma ci fa piacere comunicare che sono lì in modo che un giorno te o uno dei tuoi colleghi sia costretto a venire qua, perdere mezza giornata a cercare parcheggio e l'altra mezza giornata a tornare a MC.
  3. MS: ti vogliamo far fare un corso di comunicazione molto utile nel caso in cui cambi progetto e ti dobbiamo colloquiare presso altri clienti. Sticazzi se non hai neanche uno straccio di certificazione su Java o su altri framework, ti pare che quello che fai effettivamente a lavoro è importante? AHAHAH ma noooo! Devi essere bravo a parlare con il cliente, a leccargli bene il culo, a non incrociare le braccia mentre ti colloquiano e soprattutto a parlare bene della tua azienda, di quanto fattura, di quali clienti ha e di quanto semo forti e di quanto ce l'abbiamo grosso! Chissene frega se hai passato il 99,99% del tempo fuori MS, l'importante è che tu sappia fingere bene!


Per fortuna chiuderò a presto i rapporti lavorativi perché avevo bisogno principalmente di cambiare progetto, ambiente e soprattutto perché ho bisogno di sentire la sensazione di essere pagato il GIUSTO per tutto quello che ho fatto e so fare!


Di questo e di tanto altro cercherò di parlarne nei mei successivi post, semmai ce ne saranno.


Finisco questo post rispondendo ad una sola domanda (ipotetica):

Perché proprio Java?

Beh le alternative erano solo due: Java o .NET. E col cazzo che mi facevo legare alle porcherie della Microsoft per il lavoro.


Ciao mondo infame.