C# 7.2 piccole novità: ref on extensions


wood-grain-1498938249NHu

In C# 7 questo non era possibile:

public static class Extensions
{
   public static void Something( ref this ExtendedStruct es)
   {
   }
}

Non era cioè possibile passare ad esempio una struct ad un extension method per reference, pagando quindi pegno se volevamo usare extension method su strutture.

Con C# 7.2 adesso è possibile, ci sono altre novità che riguardano “ref”, forse più interessanti ancora. Novità tutte orientate a tenere sempre più in considerazione le performance.

author: Mauro Servienti | posted @ Wednesday, December 6, 2017 2:47 PM | Feedback (0)

C# 7.1 piccole novità: AsyncMain


i-am-waiting

Una delle cose “noiose“ quando si scrive un’applicazione, ad esempio, Console è quando nel metodo Main si deve avere a che fare con codice asincrono, si finisce per scrivere una cosa del tipo:

public void Main(string[] args)
{
   MainAsync(args).GetAwaiter().GetResult();
}

public Task MainAsync(string[] args)
{
   return Task.CompletedTask;
}

che ultimamente si può ulteriormente accorciare in:

public void Main(string[] args) => MainAsync(args).GetAwaiter().GetResult();

public Task MainAsync(string[] args)
{
   return Task.CompletedTask;
}

Usando i nuovi expression-bodied members. Con C# 7.1 si può finalmente eliminare la parte sincrona, limitandosi a scrivere:

public static async Task Main(string[] args)
{
   return Task.CompletedTask;
}

Le funzionalità nuove sono opt-in e devono essere attivate nel file di progetto aggiungendo ad esempio:

<PropertyGroup>
   <LangVersion>latest</LangVersion>
</PropertyGroup>

author: Mauro Servienti | posted @ Monday, December 4, 2017 9:56 AM | Feedback (0)

Non c’è scritto da nessuna parte che i messaggi vengano consegnati o processati


pexels-photo-292426

Abbiamo già detto che esiste solo oneway-messaging e che exactly-once delivery è una chimera, per continuare la mia carrellata di buoni motivi per non impelagarsi in un sistema distribuito oggi vorrei introdurvi al magico mondo delle poison queue.

Quando un messaggio viene inviato possono succedere le seguenti cose:

  • L’infrastruttura non riesce a consegnarlo alla coda di destinazione
  • Il messaggio arriva alla coda di destinazione malformed
  • Il destinatario riceve il messaggio ma fallisce nel processarlo

Come più volte ho ribadito in un sistema basato su messaggi la perdita di un messaggio porta all’inevitabile corruzione dei dati, ergo perdere un messaggio è cosa quantomeno poco simpatica.

Nei primi due casi di cui sopra l’infrastruttura di solito ci viene in aiuto con il concetto (quasi sempre) built-in di poison queue. Quello che succede è che è possibile definire una coda da usarsi come parcheggio per i messaggi che non possono essere consegnati o che sono malformed.

Il terzo caso è un po’ al limite, tecnicamente il messaggio è buono ed è stato pure consegnato, ma il destinatario fallisce nel processarlo, per colpa, ad esempio, di un bug viene sollevata un’eccezione. Ne consegue che il messaggio resta in coda, in testa alla coda, con il rischio quindi che venga riprocessato, e riprocessato, e riprocessato, e riprocessato, all’infinto. Causando una sorta di denial of service al destinatario per colpa del destinatario. In base all’infrastruttura anche un messaggio malformed potrebbe portare allo stesso identico scenario.

In questo terzo caso avete quindi bisogno che il vostro codice sia in grado di dire all’infrastruttura: basta, non farmelo più vedere e spostalo in una poison queue.

Ovviamente ci ritroviamo in uno scenario interessante:

  • Il mittente ha mandato un messaggio, e come abbiamo detto non ha alcuna possibilità di sapere come stanno le cose
  • Il destinatario non l’ha mai ricevuto o l’ha ricevuto e ha fallito nel processarlo
  • Il messaggio sta bello bello, buono buono, in una poison queue

Abbiamo quindi bisogno di fare monitoraggio delle poison queue, di capire perché i messaggi sono finiti li, e infine ove servisse di riprovare a consegnare i messaggi.

author: Mauro Servienti | posted @ Friday, December 1, 2017 10:19 AM | Feedback (0)

Exactly-once delivery è una chimera


oct_12_2003_delivery

Abbiamo già spiegato perché esiste solo one-way messaging, oggi cerchiamo di sfatare un secondo mito: exactly-once delivery. Che altro non è che l’aspettativa che un messaggio sia sempre consegnato una ed una sola volta.

È possibile?

Si, in un solo scenario:

un trasporto transazionale con il supporto per il DTC in combinazione con un processo di gestione del messaggio che è in grado di fare enlistment nella transazione distribuita.

Quindi se avete MSMQ con le code transazionali, tutto quello che fate quando processate il messaggio è lavorare ad esempio con un database su SQL Server, e infine decidete di accettare di pagare l’obolo del DTC, ecco, siete in grado di gestire il seguente scenario:

  • Il messaggio è in coda
  • Il processo client lo scoda iniziando una transazione con la coda
  • La fase di processamento scrive dei dati su un database transazionale
  • Il processo client committa la transazione
    • Il messaggio viene cancellato dalla coda come processato
    • I dati sono nel DB
  • Qualsiasi cosa vada storta il processo client fa rollback della transazione ed è come se nulla fosse successo

Ovvio che se invece di parlare con un database transazionale stessimo parlando con un endpoint HTTP c’è poco da fare rollback, il messaggio verrebbe riprovato e la chiamata HTTP rifatta. Prima di affrontare questo secondo problema vediamo cosa succede con un trasporto che non va a braccetto con il DTC.

Amazon SQS: at-least-once delivery semantics

Dal punto di vista infrastrutturale Amazon SQS è un broker, internamente per garantire affidabilità e scalabilità l’infrastruttura è basata su repliche master-master, questo significa che una coda X è replicata su più nodi.

Vediamo cosa succederebbe con MSMQ in uno scenario simile: cluster.

  • 4 macchine con MSMQ
  • Windows Network Load Balancing tools per definire il cluster
  • I mittenti vedono una sola coda, quella del cluster
  • Quando un messaggio arriva in realtà arrivano 4 messaggi identici nelle code locali di ognuna delle 4 macchine
  • Inizia una transazione distribuita che porta al consenso su chi processerà il messaggio effettivamente
  • Come potete immaginare, o sapere se avete nozione degli internals del DTC, all’aumentare delle risorse coinvolte nella 2 phase commit diminuiscono le prestazioni. Cioè il tempo impegnato per garantire exactly-once delivery cresce al crescere della richiesta di affidabilità e anche di scalabilità, che è un controsenso: voglio più potenza di fuoco ma la più potenza inficia la potenza di fuoco stessa.

I vendor quindi scappano a gambe levate dal DTC verso il concetto di visibility timeout (ce ne sono svariate implementazioni), il che vuol dire che nell’esempio di cui sopra il dialogo è più o meno il seguente:

  • 4 macchine con i nodi della coda di nostra scelta, ad esempio SQS
  • tools per definire il cluster
  • I mittenti vedono una sola coda, quella del cluster
  • Quando un messaggio arriva la struttura master-master fa si che arrivino 4 messaggi identici nelle code locali di ognuna delle 4 macchine
  • A questo punto una delle 4 dice: preso, è mio per i prossimi x secondi
  • L’infrastruttura master-master propaga questa informazione al cluster e gli altri 3 stanno li buoni buoni nascondendo il messaggio agli eventuali client

Adesso fate scale-out anche dei client, introducendo il così detto modello competing consumers. Quindi 2 client identici, su due nodi diversi, che guardano la stessa coda di input.

Va tutto bene fintantoché…Il carico è moderato, ooops

Al crescere del carico, numero di messaggi ricevuti per secondo, quello che può facilmente succedere è che questo:

  • A questo punto una delle 4 dice: preso, è mio per i prossimi x secondi
  • L’infrastruttura master-master propaga questa informazione al cluster e gli altri 3 stanno li buoni buoni nascondendo il messaggio agli eventuali client

Non si propaghi abbastanza velocemente e se due dei client di cui sopra per sbaglio stanno guardando due nodi diversi (shard) del cluster ecco che entrambi cominciano tranquillamente a processare lo stesso identico messaggio. At-least-once delivery servita su un piatto d’argento.

Nel frattempo dietro le quinte il visibility timeout si è propagato, quindi il nodo che per ultimo darà l’ACK al cluster confermando di aver processato il messaggio riceverà un errore e avrà la possibilità di fare rollback, sempre che possa ovviamente.

Ho usato SQS come esempio perché è quello dove è più facile che il problema si presenti, Azure ServiceBus è anch’esso at-least-once ma i namespace riducono lo scope, facendovi vedere solo un sottoinsieme del cluster riducendo l’impatto del problema, ma introducendo altri problemi che non sono oggetto di questo post.

Dobbiamo preoccuparci?

Neanche per sogno, dobbiamo però sapere bene che come un messaggio potrebbe non essere mai processato allo stesso modo potrebbe essere processato più volte.

Il nostro sistema deve essere ben conscio di tutto ciò e deve accettare che exactly-once delivery non scala o addirittura è impossibile. Ha quindi molto più senso fregarsene e spostare la nostra attenzione su exactly-once processing.

Alla prossima.

author: Mauro Servienti | posted @ Wednesday, November 29, 2017 12:29 PM | Feedback (0)

Perché esiste solo one-way messaging


q

Prima di addentrarci e scoprire cosa possiamo fare con una coda e ovviamente dei messaggi, cerchiamo di dare una risposta definitiva al perché “two-way messaging” non abbia senso, e quindi esista solo “one-way messaging”. Quando si parla di code abbiamo due macro tipologie di architetture:

  • store & forward
  • broker

Un ottimo esempio di store & forward, e pure l’unico che a quest’ora di mattina mi viene in mente, è MSMQ. Per mandare un messaggio da A a B:

  • A manda un messaggio alla sua coda locale di uscita, la coda locale è sulla stessa macchina su cui vive A
  • la coda locale di uscita quando avrà connettività cercherà di mandare il messaggio alla coda di input di B sulla macchina remota
    • Se l’invio fallisce il messaggio viene spostato in una dead-letter queue
    • Se l’invio non avviene entro il timeout prestabilito, concettualmente è come se avesse fallito, di nuovo dead-letter queue

Nel caso dei broker, ad esempio RabbitMQ, quello che succede è:

  • A manda un messaggio al broker chiedendo di consegnare il messaggio a B
    • Se non c’è connettività con il broker A scoppia immediatamente
  • Il broker, supponendo la configurazione più restrittiva possibile:
    • Manda un ACK ad A confermando la ricezione del messaggio
    • Informa anche A che la destinazione esiste, quindi la coda di B è effettivamente cosa nota
  • A seconda della tipologia di clustering del broker stesso non è detto che la coda di B sia effettivamente raggiungibile

Dal punto di vista dell’infrastruttura, se osservate i dialoghi di cui sopra, come mittenti il meglio che possiate ottenere è: il messaggio che ho inviato è stato consegnato nella coda del destinatario, oppure la consegna è fallita. In nessun modo avete possibilità di sapere se il messaggio sia stato processato con successo o se nel momento in cui è stato processato vi sia stato un errore, perché per l’infrastruttura questa informazione può essere consegnata solo con un altro messaggio, e quindi siamo di nuovo al problema dei due generali. Come abbiamo già detto l’unico modo che avreste è tenere in piedi una transazione distribuita tra tutte le parti coinvolte, ma è un ossimoro, perché introduciamo code proprio perché vogliamo rendere indipendenti mittente e destinatario.

Le implicazioni di questo “piccolo” dettaglio sono importanti, prima su tutte è l’impatto che il non poter avere certezza che una richiesta sia stata processata ha su come viene disegnato un sistema. Ecco quindi spiegato perché quando si parla di sistemi distribuiti si parla di “design for failure”.

Ricordatevi sempre che la prima regola di un sistema distribuito è: non è vero che avete bisogno di un sistema distribuito ;-)

author: Mauro Servienti | posted @ Monday, November 27, 2017 7:01 AM | Feedback (0)

“wanna be architect”


image

Settimana scorsa a Torino, durante una delle pause, un ragazzo mi chiede: come faccio a diventare un architetto? La domanda credo nascesse dal fatto che sulle mie slide c’è scritto “Solution Architecth @ Particular Software”. La mia risposta è stata molto semplice: a suon di schiaffoni :-)

In tutta sincerità sul mio biglietto da visita c’è scritto Solution Architect, ma la bio interna inizia così:

image

Non credo che un professionista possa mai dire di avere abbastanza esperienza per definirsi un Solution Architect. Semplicemente per il motivo che ogni soluzione e l’architettura che l’accompagna sono talmente dipendenti dal contesto che avremo sempre qualcosa che non abbiamo mai sperimentato prima. Un problema nuovo che ci coglie totalmente impreparati.

Gli schiaffoni, derivanti dai progetti falliti o non proprio delle perfette ciambelle col buco, sono la cosa che ci fa crescere e accumulare esperienza, esperienza che si può spendere, con tanta umiltà, su queli problemi ignoti di cui sopra.

L’esperienza non si insegna con un corso, e per fare esperienza ci vuole tempo, quindi la vedo dura essere Solution Architect a 25 anni, ma non cercherei neanche di aspettarmi da un neo laureato che abbia nozioni, esperienza e calli a sufficienza.

Quindi:

come faccio a diventare un architetto?

  • sperimentando, fallendo e imparando dai propri errori
  • mettendosi in gioco e confrontandosi con gli altri
  • ovviamente studiando
  • senza fretta soprattutto, spendersi troppo presto può essere controproducente

Piccolo spazio pubblicità: 5 giorni con Udi aiutano, ma non sono la base di partenza, piuttosto un check-point da fare lungo la strada.

author: Mauro Servienti | posted @ Wednesday, November 22, 2017 12:17 PM | Feedback (0)

Il coach ha sempre torto


swimmer-1678307_1920

Nuoto, da ragazzino nuotavo. Sono anche bradicardico, a 44 anni ho ancora 46/48 battiti a riposo a volte anche meno. Ne consegue che la mia specialità è sempre stata il fondo. Quindi 800, 1500 o oggi le tipiche distanze da triathlon o di più. Da ragazzino avevo un difetto, sulle lunghe distanze a stile libero nelle ultime vasche tendevo a smettere di fare la classica virata con capriola (flip turn) in favore della virata tradizionale. L’allenatore del tempo sosteneva che fosse solo ed esclusivamente una questione di paura, l’aspetto psicologico prendeva il sopravvento e verso la fine tendevo ad evitare le cose rognose. Peccato che il personaggio insistesse nel sottolineare che io avessi paura. Lui era il coach, quello che sapeva, quindi aveva per forza ragione.

Peccato che non capisse un cazzo, ma io non avevo a quell'età nessuna base per comprendere che il problema fosse lui.

Una delle cose fondamentali nel nuoto è la respirazione, lo è in tutti gli sport ovviamente, ma nel nuoto c’è il dettaglio che non respiri quando decidi tu, ma solo quando hai la testa fuori. La respirazione è quindi influenzata dal ritmo della bracciata. Quando la tecnica è buona il tempo in cui mezza faccia è fuori dall'acqua per respirare è tipicamente pochissimo. Questo fa si che nel nuoto la respirazione è si importante ma l'espirazione è fondamentale.

Se si espira male, leggasi non a fondo, si accumula CO2 nei polmoni, nel tempo che la mezza faccia sta fuori l'aria che si è in grado di immettere si riduce perché i polmoni non sono abbastanza vuoti, debito di ossigeno –> iperventilazione –> dispnea. Ovvio che iperventilare mentre si nuota non è molto fattibile, ergo dopo qualche vasca la virata con capriola diventa una rogna perché il tempo di apnea è decisamente superiore a quello della bracciata.

Il segreto è semplice: espirare con tutta la forza possibile prima di tirare fuori la testa per respirare, fine de giochi. Semplice ed efficace. E quello era uno stronzo.

Quindi? direte voi…

Il succo della questione è che fare il coach o il mentor è un lavoro difficile, molto difficile. Ogni volta che vostro allievo o mentee non ci viene dietro la prima cosa da fare è mettere in discussione noi stessi in quanto coach o mentor. Analizzando il nostro comportamento alla ricerca di falle ed errori.

BTW, nuotare è un ottimo modo per meditare.

author: Mauro Servienti | posted @ Monday, November 20, 2017 12:20 PM | Feedback (0)

WebAppConf - il giorno dopo


Turin_monte_cappuccini

Ieri ho avuto il piacere di essere ospite alla WebAppConf a Torino. I ragazzi di Corley confermano essere degli ottimi organizzatori e hanno per l’ennesima volta prodotto un evento degno di nota, con grande seguito, e con alcune novità interessanti.

Andiamo con ordine, il materiale della mia sessione introduttiva, molto introduttiva, su GraphQL è on line.

Il formato 30 minuti, o 45 al massimo, mi piace sempre di più. Obbliga ad essere sintetici e a rimuovere tutta la fuffa di contorno. Offre anche molta più varietà ai partecipanti perché permette di raddoppiare gli argomenti trattati offrendo una maggior possibilità di essere soddisfatti. È anche possibile fare qualcosa di approfondito in 30 minuti, non è facile ma si rivela una bella sfida per lo speaker.

La novità a questo giro sono state le sessioni di mentoring, speaker e mentor erano a disposizione per sessioni di 10 minuti con i partecipanti. Sessioni il cui formato era il seguente:

  • 2/3 massimo per i partecipanti per esporre il loro problema
  • Il resto del tempo per intavolare una discussione
  • Divieto assoluto di cercare di vendere qualcosa

Ne ho fatte tre, sono state interessanti e spero efficaci per chi partecipava. Io dal canto mio le ho trovate formative.

By the way:

  • l’evento era a pagamento e nonostante questo è andato sold-out in pochissimo tempo, con un drop rate pari a zero.
  • La sessione che mi è piaciuta di più è stata quella di Andrea De Carolis, meritava di essere usata come sessione di apertura. Zero tecnologia e tanta ispirazione. Ottimo lavoro.
  • “Purtroppissimo” a sto giro non posso essere parte della CloudConf 2018, ma è certo che non mi faro sfuggire le prossime edizioni.

author: Mauro Servienti | posted @ Friday, November 17, 2017 1:49 PM | Feedback (0)

Esiste solo one-way messaging


2000px-MUTCD_R6-1R.svg

Molti di quelli che si approcciano al fantastico mondo della architetture distribuite basate su messaggi partano da un presupposto che non trova conferma e che tende ad essere fuorviante specialmente in fase di design.

Non esiste 2-way messaging

Spesso e volentieri quando si parla di messaggi si parla di pattern come request/response, request/reply e/o pub/sub. Nello specifico i primi due sono quelli che corrono il maggior rischio di essere fraintesi.

Se osserviamo come funziona un’infrastruttura di messaggistica, broker o code che siano, non esiste alcuna implementazione di request/* ma esiste semplicemente “request”, o più grezzamente esiste semplicemente la possibilità di inviare un messaggio. Se proprio vogliamo essere ancora più precisi non esiste neanche questo, piuttosto quello che le infrastrutture di messaggistica vi offrono è:

  • Accetta questo messaggio il cui destinatario è XYZ, e, se lo supporti, dammi conferma di averlo accettato (non consegnato, solo accettato).
  • Cortesemente, garantiscimi che se non riuscissi a consegnare il messaggio lo metti in un posto in cui non da fastidio, ma sia accessibile. L’importante è che non perdi il messaggio.

Fine.

Ogni altro tentativo di fare qualcosa di più sofisticato implicherebbe il noto problema dei due generali e l’unica possibilità di evitarlo sarebbe una simpatica transazione distribuita tra mittente, infrastruttura di messaggistica e destinatario. Cosa che ovviamente ci fa inorridire perché è uno dei motivi per cui abbiamo scelto un sistema di messaggistica.

In soldoni questo significa che da parte del mittente è impossibile sapere se il messaggio sia stato consegnato al destinatario. Non ci sono vie d’uscita, facciamocene una ragione.

Se osserviamo le due regole base di cui sopra, il massimo a cui possiamo aspirare è che o il messaggio è nella coda di destinazione, ma nulla ci può dire che sia stato processato correttamente, o nella peggiore delle ipotesi sta in una coda di errore, poison queue.

Questo comporta quindi che data una request che si aspetta una response non c’è nulla che garantisce che quella response sarà mai inviata, semplicemente perché non c’è nulla che garantisce la request sia mai andata dove speriamo che vada.

Vogliamo disaccoppiamento? Ci dobbiamo portare a casa anche le rogne del disaccoppiamento.

Questo principio fondamentale è quello che ci deve far sempre e solo dire: design for failure.

Nelle prossime puntate cercheremo di capire:

  • Il perché tecnologico di quello che abbiamo detto guardando a come funzionano i due principali modelli di messaggistica: store & forward e broker
  • Che cosa sono quindi pattern come request/* e pub/sub
  • Che cosa vuol dire di conseguenza “design for failure”

author: Mauro Servienti | posted @ Wednesday, November 15, 2017 10:25 AM | Feedback (0)

La collaborazione è più importante della produttività


team-1928848_1920

Internamente stressiamo moltissimo su quelli che comunemente vengono definiti soft skills, ad un punto tale che più volte è stato dichiarato che la collaborazione è più importante della produttività, la maggioranza dei nostri processi sono orientati a favorire la collaborazione e la comunicazione piuttosto che la produttività. Che in altre parole può essere letto come: ci interessa essere più efficaci che efficienti.

Nel nostro scenario distribuito la collaborazione assume ancora più valore, se fossimo orientati all’efficienza (e quindi fossimo troppo attenti a quanto produciamo) rischieremmo con facilità di orientare i processi a quello con la spiacevole, e presumo inevitabile, conseguenza che collaborazione e comunicazione morirebbero soffocate dalla produttività.

Nel nostro mondo in cui l’intelletto la fa da padrone e non siamo macchine non senzienti c’è comunque un alto rischio di scivolare troppo verso la produttività, dimenticandosi i soft skills, anche in realtà non necessariamente estreme come la nostra.

In questo senso vorrei una standing ovation per questo tweet:

image

E voi che realtà vivete?

author: Mauro Servienti | posted @ Monday, November 13, 2017 3:58 PM | Feedback (0)