L’importanza dell’ambiente di sviluppo

Questo titolo altisonante e’ il preambolo di una considerazione estremamente semplice :

Niente come un ufficio con un frigo pieno di birre e una quantita’ spropositata di tacos e salsetta piccante rende il venerdi’ pomeriggio produttivo.

600 righe rifattorizzate in 4 pomodori!!

Ora basta che il tutto riesca a integrare, ma lo spirito alcolico mi porta alla fede.

Nel segreto dell’urna elettorale

Silvio ti vede, Walter no!

Ho pensato di commemorare i recenti risultati elettorali con questo adattamento di un celebre slogan da un’altra epoca. Ma sara’ poi davvero un’altra epoca?

Nella mestizia per il risultato generale ci sono pero’ spruzzi di estasi grazie alla lista degli esclusi.

Ora il grido dev’essere uno solo : “Tenete ben chiuse quelle finestre!”

Questa mattina commentavo placidamente che da ieri potrebbero anche ridurmi lo stipendio. Di colpo il fatto di non vivere in Italia mi fa percepire un immediato valore aggiunto.

Abstractions

As usual, since I’m commenting something that was written in English I post in English.

I have got a solid respect for Joel Spolsky, he certainly is a professional who knows what a programmer is and how to explain it in clear, strong, words. He is not a paramount for me though and I would go as far as saying that in his posts his chief weapon is rounding up to the biggest whole value (and yes, this is kind of a monty python’s quote).

This often forces me to mentally prune and edit his posts in real time to avoid getting bad feelings while reading stuff that would otherwise have good value to me. So, let me say I dislike his style despite the fact that I reckon he is a great communicator.

One of Joel’s most famous statements is the law of leaky abstractions. It is of course a very controversial statement and its conclusions seem to deny the value of abstraction itself.

I believe neither is true.

It is not a controversial statement as it is just a rephrasing of basic and well-accepted software engineering concepts : an abstraction is a simplification of reality created to more easily address a specific facet of a problem.

It does not deny the value of abstraction either.

Abstractions do have contracts, thus conditions for them to act accordingly to their contracts. A failing abstraction is still an abstraction, it is telling you that the conditions for it to work are not met, which narrows down the issue. A huge value.

I came to think once more about the law of leaky abstraction due to a weird issue with a wi-fi printer I had bought and installed at my parents’ home.

The printer is an HP C4380. Somehow it worked well enough with USB, but when used through wifi it printed only the first 2 lines of the first page. Incidentally, the printer’s own installation software had reported inability to connect to the printer, but I was able, for instance, to query the printer for ink levels, status and other data.

I’ll spare you the details, but after three hours I found out why the print command was failing (which I could state as : “I can obtain a paper-based copy of the document I got on the screen by asking the printer to print it”).

It was because this fancy printer has an MTU of 1466 bytes.

Such genius in the creation of a printer is astonishing, but, nonetheless, by taking a step beyond the basic abstraction, and then more layers, such as WIFI, then TCP, then IP, then Ethernet I finally restored the failing condition : “The sender must use transfer units of equal or smaller size of the receiver”.

Was the abstraction leaky? No, it just required that the underlaying abstractions had their conditions met, which in turn involved more conditions and further layers to have their own conditions met as well.

Returning to Joel’s excellent TCP-IP example: even if mice chew the cable in half my abstraction of TCP will not “leak”, it will return an error, which is perfectly within the definition of the TCP abstraction. The error will be properly abstracted, mind you : just a timeout, not, for instance, a list of packets whose retransmission failed.

This is Joel’s “upper approximation”: he purposefully presents the fact that abstractions have conditions for their validity in a way that makes one believe the whole idea of abstraction is moot. He does not say so, mind you, but so it sounds; the world “leak” is picked on purpose and this is why the law attracted so much attention.

How to manage a failing abstraction? Joel uses the necessity of inner-protocol knowledge to prove that indeed one cannot fully rely on abstractions. But they were never supposed to be fully reliable, if so, they would not abstract away any detail!

This is very clear if one delves in long-lost memories : “If we presume the angle of incidence is small enough, we can apply first-order gaussian formulae to lens-focus calculation”. That’s an abstraction, a model for reality, that simplifies a given aspect of the problem by providing a condition to the application of the abstraction.

It is not very different from saying : “If there exist a live routed path to a given destination (add here a lot of other conditions) TCP will guarantee delivery”

Why do we use abstractions to model reality since they are not almighty and will work only if the conditions are right? We ultimately do so to split concerns among different people. By letting some people take care that the conditions for a given abstraction are supported we can assign some other people to the task of using that abstraction.

These two acts (taking care the conditions are met and using the abstraction) can then be geographically-spaced and time-spaced.

What if the abstraction stops working? Then someone should restore the conditions for it to work, if that someone is your own people then you might be able to fix it sooner than later, which is better, of course.

But this doesn’t mean that you need to have people for recreating all of the required conditions.

As long as you can presume such conditions are maintained by the system in the long term you can define them as “reliable infrastructure”. Which means : “I will spare with learning how to restore the nominal conditions of an abstraction for the sake of devolving more resources to using it”.

You don’t need to have Java programmers who are also Electricians, nor Bakers. But since you are presumed to create your own networking infrastructure, you likely prefer to have programmers who know about what an MTU is.

If you can presume your networking as reliable infrastructure, you can spare with that requirement for your programmers.

One hardly presumes that the abstraction “I can obtain bread by using money” will ever break. But if it does, it is not because “abstractions are leaky”, but because abstractions do have conditions. The reliability of a system is the chance such conditions might fail.

(Later addition, forgot to add it at first)

My parents didn’t presume they would need a trained technician to print a document, since they got one at hand they could have their system meet the required abstraction conditions (changing the MTU of the pc to be smaller than the printer’s), but they could have stayed at their own abstraction layer by following the suggested solution which was included in the manual (error responses) return the printer and pick a new one.

Then again, this is hardly a surprise for anyone. To be forced to accurately ponder which layers to consider as fully reliable and adequate for a given project is a mainstay of technical and general planning.

Il cambio delle lampadine

Una metafora sul codice, che ne riprende mille altre simili, e’ tornata alla mia attenzione negli ultimi giorni :

“Devi cambiare una linea di codice, sai gia’ qual’e’, e’ come sostituire una lampadina!”

Non ero coinvolto nella discussione e non ho commentato subito, ma in questi giorni ci ho riflettuto molto.

Credo che questa, e altre metafore dello stesso tipo, nascano dalla limitatezza espressiva del codice nel descrivere le proprie interconnessioni.

Se ci si limita a un’occhiata, la linea di codice “sembra” isolata, come sono isolate le voci di un elenco telefonico. Questa carenza espressiva nel codice permette di creare metafore del tutto fuorvianti, ma dal forte appeal.

Cosi’ come il codice, progetto della macchina che il compilatore costruira’, lo schema elettrico di un edificio, progetto della successiva installazione concreta del sistema elettrico, espone dei punti in cui e’ possibile effettuare una semplice sostituzione e aspettarsi di mantenere la coerenza del resto del sistema.

L’attacco di una lampadina e’ proprio uno di questi punti.

Altri punti dello schema elettrico invece non condivideranno questa qualita’ : come non citare l’esempio della ventola del mio bagno, che ha cominciato a funzionare solo dopo aver attaccato i fili della lampadina del bagno, perche’ proprio da questi alimentata?

La metafora del cambio della lampadina per descrivere la modifica di una linea di codice e’ corretta solo se quella linea di codice condivide le caratteristiche della lampadina : un oggetto che incapsula completamente le funzionalita’ desiderate (produrre luce) con un’interfaccia (l’attacco, il consumo, la polarita’) che ne astrae i dettagli implementativi.

Non a caso, quando nel codice si ci trova a rispettare tali proprieta’, sostituire una linea e’ semplice proprio come cambiare una lampadina.

Queste proprieta’ pero’ non sono comuni: tipicamente le linee di codice che le rispecchiano sono quelle in cui avviene l’istanziazione di una classe concreta dentro ad una variabile astratta (supposto che l’implementazione rispetti pienamente il contratto dell’astrazione).

Ecco, linee di questo tipo sono rapidamente sostituibili :

CalcolatoreDelMutuo calcolatore = new CalcolatoreMutuoQuinquennaleBancaIbs();

con altre lampadine :

CalcolatoreDelMutuo calcolatore = new CalcolatoreMutuoDecennaleBancaOpl();

Da qui nasce il valore della composizione : moltiplica le linee di questo tipo.

Sfortunatamente nel classico sistema di media-alta complessita’, dal design, diciamo, non perfetto, ci sono pochissimi punti di astrazione con il necessario grado di disaccoppiamento e sostituibilita’. Cosi’ pochi da rendere statisticamente improbabile che una linea da modificare ricada tra quelle fortunate.

La maggior parte sono linee che non rappresentano punti di aggancio di lampadine, quanto piuttosto fili di interconnessione, che su uno schema elettrico sono proprio rappresentati da linee, giunzioni e altri elementi non modulari.

Cambiare quindi una linea di codice corrisponde piu’ comunemente a cambiare un filamento a incandescenza che corre da una stanza all’altra e finisce dritto nelle prese a muro di due stanze diverse.

Visto che il filamento non e’ mai uguale agli altri ed essendo in serie a tutto il circuito, cambiarlo corrisponde a modificare lo schema elettrico del sistema.

Se ogni linea di codice ci sapesse mostrare le sue interconnessioni a monte e a valle sarebbe un gran guazzabuglio, ma sicuramente non nascerebbe l’idea di poterla “sostituire”. Infatti non diciamo “Facile come creare una derivazione al terzo piano”. Lo schema elettrico e’ molto chiaro nel definire cio’ che e’ modulare ed astratto da cio’ che e’ particolare, concreto e quindi fragile.

La sostituibilita’ e’ una caratteristica rara che richiede accurata levigatura per poterla raggiungere e anche cosi’, sempre e solo nel senso di definizione dell’astrazione. Non diciamo certo “facile come cambiare una lampadina con un asciuga capelli”.

Quindi, volendo proprio trovare una metafora elettrica per la modifica di un software fortemente interconnesso potremmo fare cosi’:

1000 linee di codice sono lo schema elettrico di un piano di un palazzo e ogni linea tracciata sul piano puo’ collegarsi a una delle linee di uno qualunque degli altri piani.

Dunque quando si pensa di cambiare una linea di codice nel classico sistema legacy, la metafora corretta non e’ il cambio di una lampadina, piuttosto e’ “cambiare lo schema elettrico cosi’ che la’ dove adesso c’e’ un cavo che corre tra i piani 15,16 e 289 ci sia invece una resistenza di 5 ohm tra i piani 15 e 289. Il palazzo ha 300 piani in cui l’illuminazione e’ data da filamenti a incandescenza che corrono sospesi tra una stanza e l’altra, tutti simili, ma a loro modo diversi e quindi non intercambiabili, inoltre c’è una lavatrice in soffitta che si accende solo se premi un pulsante in cantina e altri tre pulsanti sconosciuti che incidentalmente fanno anche altre cose, oltre a garantire il funzionamento della lavatrice”.

Naturalmente per il palazzo la lavatrice e’ mission-critical.

Descritta cosi’ i costi di modifica diventano di colpo comprensibili. Non si tratta di giustificarli, quanto piuttosto ammettere il problema.

E’ subito evidente che il problema e’ lo schema elettrico e che si deve lavorare sul definire degli attacchi per lampadine, loro si’, sostituibili.

Ogni giorno si lavora per aggiungere una lavatrice in giardino e un ferro da stiro nella hall, ma con pari priorita’ si deve anche evitare in qualche modo di essere costretti ad alimentarli con un pannello solare nello sgabuzzino illuminato coi filamenti a incandescenza del pianerottolo di sotto.

Il vero guaio, a livello di comunicazione tra persone di ambiti diversi, e’ che certe metafore, valide per sistemi fortemente ingegnerizzati, trovano riscontro in quasi tutta la tecnologia che ci circonda e quindi hanno una componente di innegabilita’ che contagia anche coloro che sanno perfettamente cosa significhi davvero cambiare una linea di codice. Figuriamoci qualcuno il cui principale, e comprensibile, interesse e’ guadagnare il pane mettendo un’altra lavatrice in giardino.

Per il committente l’immagine di associare alle linee di codice altrettanti punti di sostituibilita’ ha una forza data dall’immediatezza delle proprie esperienze in contesti diversi.

Guardandoci attorno troviamo migliaia di esempi di sostituibilita’ bella e pronta : il cibo, le lampadine, le lavatrici, i vestiti.

Se la nostra esperienza quotidiana fosse invece quella di usare prototipi di microprocessori e dover cambiare la loro struttura per fargli smettere di moltiplicare e iniziare a sommare i grammi della nostra bilancia, assoceremmo le linee di interconnessione alle linee di codice, e i moduli intercambiabili delle memorie alle astrazioni definite nel codice.

Credo che da qui nasca l’esasperazione e l’idea che il software aziendale sia per sua natura un macello: la mancanza di vicinanza “estetica” tra una linea di codice e cio’ che e’ realmente : un dettaglio concreto dello schema progettuale di un sistema complesso, fa pensare che cio’ che abbiamo in mano sia facilmente malleabile. Una volta subìto l’ennesimo smacco a questo ordine di idee inizia a nascere ogni sorta di ritrosìa nel guardare il problema da piu’ vicino e a darlo invece per insolubile.

Come andare a spiegare a un non-tecnico che non siamo ancora stati in grado di trasformare la nostra linea di codice in un prodotto ingegnerizzato, controllato e sostituibile? Come spiegare che un tale lavoro ha un costo pari alla moltiplicazione per 5 del costo iniziale di creazione del prototipo?

Spesso, piuttosto che questa ammissione di debolezza, la forza di una metafora “di per se’ evidente” come quella della lampadina, fornisce il necessario momento di escapismo di cui ogni tecnico responsabile ha prima o poi bisogno : il committente ha le sue buone ragioni! Cambiamo questa lampadina!

Quello che conta e’, dopo aver sbottato, tornare a lavorare sul creare gli attacchi e le lampadine, ricordandosi il premio che ci aspetta: una volta che le lampadine sono state create, a un programmatore non ci vuol niente a cambiarne una o cento, proprio come ci aspetteremmo da un buon omino di casa.