Quantcast
Channel: Smartango.com
Viewing all articles
Browse latest Browse all 11

Cappuccetto rosso compra un peluche

$
0
0

Mi sono occupato di CI/CD e DevOps in azienda per molto, troppo tempo.

Il motivo principale era la mia pregressa esperienza: si perdeva troppo tempo per mettere online una nuova funzionalità, nessuno sapeva se avrebbe funzionato, nessuno si interessava di scrivere test funzionali, nessuno aveva la minima idea di cosa fossero i test funzionali.
Si finiva per fare l’upload più o meno alla cieca, dopo approvazione, che tutti puntualmente negavano di aver concesso, e dopo le lamentele del cliente, si andava dallo sviluppatore a fargli il cazziatone.
L’atmosfera entusiastica durante la pianificazione ed implementazione, si appesantiva regolarmente nel momento in cui la funzionalità andava in produzione.
Dopo alcune iterazioni, anche chi arrivava come nuovo sviluppatore, imparava ad anticipare la delusione e lo sconforto, sempre di qualche passo, fino a ledere l’entusiasmo iniziale.
“Se implementiamo questa cosa l’utente può accedere ai feed back direttamente … ma poi qualcosa si romperà sicuramente”, e così sviluppare una nuova feature perdeva immediatamente di appeal.

La correttezza con la quale l’azienda pagava gli sviluppatori non era sufficiente
a ripagare il danno in subito in termini di demotivazione.

Io ero uno di quei sviluppatori, scontenti e repressi.

Siamo una generazione cresciuta sostanzialmente senza internet, io all’età di 14 anni programmavo, era il 1989, dovevano passare ancora 5 anni prima che vedessi un modem, cresciuto in provincia, nessuno intorno a me con la mia stessa passione, almeno fino ai 16, tutto ciò che imparavo era una cosa tra me il pc, davo per scontato di non essere assolutamente capito dai miei simili, eccetera. In sostanza il condizionamento emotivo era quello dell’isolamento associato alla consapevolezza delle potenzialità enormi dell’automazione del ragionamento. Paradossalmente non ho mai pensato di essere migliore, ma solo di aver passato più tempo a ragionare, ero anche convinto che tutti sarebbero capaci di sfruttare il ragionamento: infondo è qualcosa che esiste
in natura, no?

Fu quasi per caso che durante la primavera del 2017 ascoltai un talk all’interno
del codemotion di Roma, entrai in una stanza a caso, piena di gente e dovetti stare in piedi ad ascoltare. Si parlava di leadership, lo seppi dopo un po’ che stavo lì.

Una presentazione interessante, parlava di scontento e cambiamento in azienda, di chi avrebbe dovuto portare il cambiamento, e alla fine concludeva “sii il cambiamento che vuoi vedere accadere nel mondo”. Ma “il mondo” era l’azienda, l’unico universo dove si può avere un qualche riscontro.

Era tutto molto ragionevole ed assolutamente convincente.

Allo stesso Codemotion, un dipendente di RedHat presentava un’architettura di
servizi per il deployment automatico, grossolanamente parlava di JenkinsCI, GOGS, e qualcos’altro, forse un server. I nomi JenkinsCI e GOGS si fissarono nella mia mente come il nome del fidanzato di una VIP si fissa nella mente di una casalinga.

In quel periodo non lavoravo, l’azienda era in crisi e io non ero gradito, forse
proprio perché ero “quello che combinava casini”, e comunque costavo un po’ di
più rispetto ad un interno.

Poco più tardi la crisi era talmente evidente che non si riusciva più a pagare
neanche il supporto al cliente. Così Danilo mi propose un compenso fisso mensile, io accettai, ma approfittai per fare delle richieste, porre in qualche maniera delle condizioni.

Le condizioni che potevo porre erano limitate dalla cultura aziendale stile
anni ’80: codice non condiviso e custodito nei propri server.

Prima condizione: project management. Era stato fatto un tentativo con Jira
da parte del project manager che se ne era andato da poco. Ma il tentativo
era consistito in ripetute richieste, senza successo. Avevo capito che se volevi
qualcosa dovevi essere disposto a farlo, così scelsi Redmine, in un container docker. Docker era una tecnologia che mi interessava, tutti ne parlavano e sembrava che tutti la stessero usando.

Redmine accettato. Era piuttosto importante perché lì era scritto cosa si aveva
intenzione di fare, quanti passi mancassero la realizzazione, quanto stava costando. E tra l’altro lì era scritto che quella cosa era stata pianificata, e se la messa in produzione creava casini, non era per l’opera di un pazzo che
“si era messo a toccare il server”.

Seconda condizione: docker swarm, dove spostare alcuni servizi.
Ecco, JenkinsCI e Gogs erano già in produzione prima di redmine, il fatto è che
prima di dovermi occupare del core business, stavo sviluppando una applicazione electron, ed avevo bisogno di condividere i progressi gradualmente: compilazione automatica e deploy degli eseguibili in un server dedicato.

Siamo ormai nel 2018, sono riuscito a rivedere parte del servizio che importava
i dati dal formato csv al db per aggiornare prezzi, disponibilità, descrizioni
dei prodotti. csv_reader, intuitivamente un servizio piuttosto banale, ma
col tempo il codice era diventato illeggibile, e non era stata adottata nessuna
tecnica di clean code, SOLID princicle, … nada. Lo portai a farlo funzionare,
a costo di imputarmi nei confronti di chi mi diceva “rimetti tutto a posto”
(Hakan dal supporto al cliente).

Nello swarm ogni servizio pubblicava una propria porta dalla quale si accedeva,
ogni servizio controllava il JWT nel payload per controllare l’accesso.

Fortunatamente c’era un solo servizio, capii immediatamente che la quantità di
codice ripetuto sarebbe stata un problema per il mantenimento.

Scoprii una cosa strana, Traefik. La situazione era che tutti parlavano una lingua
particolare, fatta di service-mesh, discovery service, e cose del genere.
Io imparai semplicemente che era possibile interrogare la API di docker, alla quale si poteva parlare tramite un socket unix, per scoprire ed interagire con servizi ed container che stavano girando, crearne di nuovi, eccetera.

Traefik controllava se tra i servizi attualmente in esecuzione ce ne fossero
alcuni con delle labels che poteva usare come istruzioni per esporre tali servizi
all’esterno: delle rotte da una url ad un service docker.

In sostanza Traefik è un (reverse) proxy che ascolta una porta tcp (443, https)
e in base alla request, se questa fa parte di una delle rotte create dal
servizio durante il processo di discovery, instrada il traffico al servizio
relativo.

Dall’esterno rimane solo assegnare il dominio, o domini, ad un determinato ip
dove sta ascoltando Traefik, il resto lo fa il servizio. Si può pensare ad architetture più complicate dove Traefik ascolta su più ip/macchine, girando con
l’opzione mode global service, ma questo era al di là delle mie risorse.

Dal punto di vista interno, Traefik è raggiungibile tramite una rete overlay,
condivisa tra più nodi, una rete virtuale. In sostanza Traefik tiene i piedi in
2 staffe: da una parte riceve le richieste http(s) su di un socket tcp aperto sulla
rete pubblica esposta dal server, dall’altra utilizza la rete virtuale ed il suo
servizio di risoluzione interno dei nomi (dns) per recapitare la stessa richiesta
manipolata seguendo i dettami del protocollo reverse-proxy.
Chiaramente, da protocollo, viene gestito anche il traffico di ritorno:
il servizio interno risponde al chiamante (Traefik) sopra la stessa connessione
TCP dove ha ricevuto la richiesta, e Traefik reindirizza i dati al chiamante esterno che ha iniziato la richiesta (ed ha aperto il canale TCP esterno).
Le 2 staffe sono i 2 canali TCP, ognuno su 2 reti distinte.

Dedicai l’estate del 2018 a sviluppare un tool che avrebbe permesso di accedere
ai servizi nella rete interna, ma non esponendoli direttamente a Traefik, bensì
esponendo a traefik un servizio che ascoltava un certo prefisso di url, più altri.
Ad esempio, abbiamo un servizio authenticate, che ascolta tutti path che iniziano per “https://dominio.do/authenticate/…”, e cosa va al posto dei “…” lo si definisce in un file di configurazione che viene letto all’inizio.
In pratica il file di configurazione dice:

il path “password” accetta una POST e reindirizza la chiamata ad un servizio interno “authserv_authserv” con la richiesta POST ed il payload “${body}

Inoltre il servizio espone delle labels per Traefik, cioè “io gestisco di tutti i
path che iniziano per https://dominio.do/authenticate/”

Ecco il tool in questione, API Manager, avrebbe dovuto creare i file di configurazione per questi servizi, e controllarne l’avvio e lo spegnimento.

Tutto il resto era una magia gestita da Traefik.

Mi era sembrato un compito facilmente affrontabile, non mi interessava andare a vedere se esistessero già delle soluzioni disponibili.

In effetti sviluppai API Manager in 3 mesi circa, GUI in React, backend un servizio che parlava col socket dockerd ed esponeva anche esso delle label per traefik (doveva ricevere call rest). Le image che si occupavano di instradare le richieste le chiamai gateway image, anche esse dovevano avere delle label, e c’è un servizio di discovery interno molto naive capace di riconoscerle.

Una gateway image può controllare la validità del JWT e bloccare le richieste non autorizzate, può confrontare il vettore perms facente parte del claim JWT, e bloccare o permettere oppurtuni perms.

Accesso ai servizi tutto molto scorrevole. Ma sviluppo del software ancora non abbastanza scorrevole.
La code-base era pessima e sviluppata con metodologie arcaiche.

Ciò che è peggio, e che non sono riuscito ad intaccare, è la cultura pregressa.

I test devono esistere, e I TEST DEVONO ESSERE AUTOMATICI.

I test devono esistere, devono essere automatici, e devono essere verificabili (leggibili).

I test sono un contratto (protocollo).

Il mio atteggiamento? Oggettivamente mi incazzavo, mi aspettavo che tutti dessero per scontato che scrivere i test era una garanzia per un ambiente più sano. Di fatto “ho creato un ambiente insano”, questo mi è stato detto. In realtà l’ambiente insano era già la norma, quello che ho fatto è stato solo cambiare il motivo dell’insalubrità: prima era “il sistema”, poi è diventato “Daniele Cruciani”, l’orco malefico.

C’è il vezzo di dire che gli sviluppatori non capiscono cosa gli si dice, che gli si
devono ripetere le cose in tante maniere.

Dal mio punto di vista il problema è che nelle descrizioni sono sempre presenti “zone d’ombra”, e questa ombra in qualche maniera si allunga su tutto il discorso.

Potrei dire che “si da per scontato” che tu conosca la problematica, ed in questo
“si da per scontato” che si nascondono gli integration test.

Tutti capiscono di cosa sto parlando se dico che “cappuccetto rosso indossava il capuccetto rosso”, immediatamente si attivano le connessioni alla storia, il lupo e tutto il resto, se continuo la frase dicendo “quindi il cacciatore la riconobbe per prima dallo stomaco del lupo”, tutti capiscono immediatamente.

Prova ad immaginare che tu non sappia niente della favola, del lupo, la nonna, il cacciatore, niente.

Cosa capiresti della frase:

cappuccetto rosso indossava il capuccetto rosso, quindi il cacciatore la riconobbe per prima dallo stomaco del lupo

in qualche maniera penseresti che cappuccetto rosso è un qualche tipo di animale, forse un piccolo animale da compagnia, femmina, quindi trattata come una di famiglia, deve essere qualcosa di ingeribile da un lupo, capisci che il cacciatore a ucciso il lupo altrimenti non vedrebbe dentro il suo stomaco. Forse potresti pensare che il cacciatore fosse sorpreso di averlo trovato nella pancia del lupo (“la riconobbe”).

Gli informatici si interfacciano continuamente con gente che vive nelle loro favole, e delle loro favole, ma all’inizio gli informatici non ne sanno niente delle loro favole.

Prendiamo il commercio elettronico, è chiaro che capisco che le interazioni dell’utente sono quelle di mettere un prodotto nel carrello, e la sua quantità, e alla fine procede al checkout. Ma poi intervengono molti altri sottosistemi, la disponibilità del prodotto va decrementata, deve essere creato un ordine pendente, deve essere creata una richiesta di pagamento presso un istituto o servizio esterno, si deve tenere traccia dello stato di pagamento,
e così via.

Prendiamo una possibile descrizione: “il numero di transazione del pagamento deve essere associato all’id dell’ordine nel momento in cui arriva la conferma da parte di paypal”.
Capisco che è difficile cancellare tutto quello che conosci, ma stai parlando un linguaggio tecnico senza descrivere la procedura, e questo da più l’impressione dell’atteggiamento di chi è più interessato ad accarezzare il proprio ego, che non di chi è interessato all’implementazione di un servizio.

L’argomento “non te lo dico per non caricarti di troppe informazioni” vale come quello che si aspetta che dalla frase sopra sul cacciatore si capisca la presenza della nonna.

Dirai “è ovvio che c’è la nonna”. E no. Dipende dalla tua favola.

Se non gestisci i pagamenti dei prodotti, delle transazioni paypal cosa te ne fai? Gestisci le disponibilità?
Fai gli ordini presso i fornitori? Oppure chi li fa? Cosa pagano i clienti? In quale misura?

Nessuno ha raccontato la favola. Perché i bambini si stancano ad ascoltare le favole.

Le favole “caricano i bambini di troppe informazioni”.

Dai, onestamente, non esiste questo argomento.

A certo che ho poi trattato un po’ di favole, come l’integrazione Amazon Selling Partner API, dove ho implementato tutta la procedura di creazione richiesta, controllo periodico, e download dei report. Durante l’implementazione mi si diceva continuamente “no, ma non capisci”, ed io continuamente spiegavo la procedura, la scrivevo nel codice, facevo grafici, ho anche scritto un servizio che genera i grafi di dipendenze delle varie procedure, così per stare tranquilli. C’è sempre stato quel “eh mah”, un po’ come una specie di nostalgia per i tempi andati, quando i veri uomini facevano le cosa a casaccio sperando che funzionino e poi il debug in produzione, sudate e tiratardi, pizza a mezzanotte in ufficio e puzzo d’ascelle.

Si può vivere diversamente, senza il bisogno di sentirsi degli eroi.

Credits: Immagine di ddraw su Freepik


Viewing all articles
Browse latest Browse all 11

Latest Images

Trending Articles





Latest Images