Realizzare nuove funzionalità non è il problema, decidere quali realizzare è il vero nocciolo della questione. @klabcommunity


business-2987962_1920

Anno nuovo, nuova stagione di eventi. Quest’anno per me inizia all’insegna di KLab, il 29 marzo ci troveremo a Fiorenzuola d’Arda presso l’agriturismo Mascuderia. Questa volta il tema si sposterà dalla tecnologia per dare uno sguardo alla parte metodologica.

Io dal mio canto vi racconterò tutto il lavoro che in Particular stiamo facendo per organizzare i processi relativi alla parte di “product management”, che potremmo in qualche modo paragonare con quello che Scrum assegna come responsabilità al PO.

In soldoni potremmo dire che siamo sempre stati {molto?) bravi in quanto a delivery, meno bravi in quanto a decidere cosa realizzare. Compito non facile in una realtà:

  • fluida come la nostra in cui non c’è un capo che decide il cosa il come e il quando.
  • che produce un prodotto che come utente finale ha un altro sviluppatore, il cui prodotto avrà un utente finale.

La distanza tra noi e l’utente finale fa si che i contesti d’uso del nostro prodotto siano molteplici e spesso in contrasto tra loro, le necessità di un cliente on-premise sono facilmente ortogonali a quelle di un cliente su Azure o AWS. Questa dicotomia rende spesso difficile prendere decisioni sulla direzione in cui andare. Vi racconterò il percorso che stiamo facendo per modellare l’azienda e i processi interni al fine di abbracciare questa sorta di requisito non funzionale con cui dobbiamo per forza coesistere.

Il desiderio è che sia di stimolo per tutti per magari provare a cambiare a scollarsi dal “solito modo di fare le cose”.

Vi aspettiamo numerosi, come al solito dopo si mangia!

Maggiori informazioni e iscrizioni: http://www.klabcommunity.org/klab-2018-1-ci-siamo/

author: Mauro Servienti | posted @ Wednesday, March 7, 2018 11:09 AM | Feedback (0)

Il fascino per le cose che funzionano


movement-2532158_1280

Da sempre ho una sorta di attrazione inspiegabile per le cose semplici che funzionano, soprattutto se funzionano al primo colpo. Inspiegabile perché mi rendo conto che spesso non è condivisa dai mie stimati colleghi informatici, che al contrario spesso sono attratti dalla sovra-ingegnerizzazione e dalla complessità fine a se stessa. È ovviamente una generalizzazione molto spinta, quindi non prendetevela se non siete così ;-)

Sto diventando un fan di prodotti Apple. Ho un iPhone 8, un iPad Pro di cui ho già parlato più di una volta e di cui probabilmente parlerò ancora. Da pochi minuti sono un felice possessore di una coppia di AirPods.

La cosa che mi ha lasciato per l’ennesima volta basito, molto basito, è la semplicità disarmante del setup:

  • avvicini il case al telefono
  • apri il case

Fine. Gli auricolari si connettono e si configurano. Il telefono ti dice ogni volta che nelle vicinanze apri il case:

  • quanto è carico il case, si perché il case è una batteria che ricarica gli auricolari stessi
  • quanto è carico ogni auricolare

Infine, tramite l’account iCloud le impostazioni degli auricolari si propagano a tutti i device connessi con quell’account. Quindi prendete iPad, indossate gli auricolari, avviate la musica e, boom, funziona.

Ogni volta che faccio un’esperienza di questo genere ripenso a X-Box Smart Glass e mi viene da piangere, o, in quanto bergamasco da…biiiip

author: Mauro Servienti | posted @ Friday, February 23, 2018 3:20 PM | Feedback (2)

iPad Pro Smart Keyboard…


heavy-934552_1280

Come ho detto qualche tempo fa sono un soddisfatto utilizzatore di un iPad Pro. Come dicevo ho anche acquistato la Smart Keyboard e la penna. Della non utilità della penna parleremo un’altra volta.

La tastiera invece è fatta un gran bene, se proprio devo trovare dei difetti, direi che ne ha tre:

  • Una carenza più che un difetto: la mancanza della retroilluminazione, che non è un difetto ma un nice-to-have piuttosto
  • è troppo pesante
  • manca un alloggiamento/gancio per la penna

Siccome la tastiera fa anche da cover, spesso e volentieri vi ritrovate semplicemente ad aprirla e usare il tablet in modalità touch. Per un uso prolungato l’insieme diventa troppo pesante e vi ritrovate spesso a staccare del tutto la cover/tastiera e abbandonarla da qualche parte.

Inoltre l’assenza di un alloggiamento per la penna fa si che se vi portate dietro la penna sperando di poterla utilizzare sono più le volte che rischiate di lasciarla in giro che altro.

author: Mauro Servienti | posted @ Friday, February 16, 2018 4:17 PM | Feedback (0)

È un po’ che bigio, ma ho una buona scusa ;)


2018-01-16 14.27.01

Quelle manine!

A presto.

author: Mauro Servienti | posted @ Friday, January 26, 2018 11:39 AM | Feedback (4)

Oggi sono di fretta ;-)


hurry-2119711_1280

Dedicate 3 minuti a “L’importanza dei tempi morti” di Igor Damiani.

author: Mauro Servienti | posted @ Monday, January 15, 2018 9:17 AM | Feedback (0)

SubText: l’esempio perfetto di come NON usare CQRS (o simili)


evil-bloody-clown-face

SubText, il motore che fa girare questo e tanti altri blog non è mai stato eccelso ma ha sempre fatto il suo sporco lavoro e lo ha fatto spesso e volentieri bene. L’ultimo aggiornamento l’ha invece trasformato in un robo pressoché schifoso. La sensazione, perché in tutta sincerità non ho idea di come funzioni, è che i dati che la parte di front-end vede arrivano da ElasticSearch (o da una cache), mentre quello che la parte di back-end vede arriva da un database relazionale, o qualcosa di simile. Sembra quindi una sorta di implementazione di CQRS.

Ecco lasciatemi dire che questo è esattamente come non deve essere implementato CQRS, mi spingerei anche verso il: che diavolo di senso c’è nell’usare CQRS per un blog.

image

La consistenza eventuale tra quello che vede il front-end e quello che vede il back-end è di minuti, spesso decine di minuti. Qui sopra un post, che secondo la UI di front-end non ha commenti, mentre secondo quella di back-end ne ha ben due, è passato un tempo interminabile prima che i commenti comparissero anche lato front-end. E forzare la ricostruzione degli indici di ElasticSearch non è servito a nulla, il che mi fa pensare che non sia in modalità pull.

image

Lasciamo perdere poi chicche come la seguente, lato back-end post duplicati, che dopo un po’ scompaiono.

image

Perché in stile CQRS?

Questa è la domanda vera, che senso ha applicare CQRS ad un blog engine. Un blog engine è un generatore statico di contenuti, scrivo una volta, difficilmente modifico, leggo un’infinità di volte. Il rapporto letture/scritture è tremendamente a favore delle letture, l’unica cosa su cui c’è interazione sono i commenti, che nell’implementazione di SubText attuale sono complementi inutilizzabile per avere qualsivoglia sorta di interazione.

Il giro corretto dovrebbe essere:

  • scrivo
  • pubblico un contenuto statico
  • commento
  • cerco nei contenuti del blog

Considerando che i commenti sono solo testo, e non sono ne threaded ne ricercabili/indicizzati, cosa c’è di male nello schiaffarli piatti in una schifosa tabella relazione e leggerli da li. Se i contenuti sono statici per definizione non impattano sul DB, possono essere messi in cache pressoché all’infinito, l’unica cosa da caricare dal db sono i commenti.

Se proprio voglio cercare, allora si che posso far macinare il testo dei post ad ElasticSearch a indicizzare lo slug del post stesso.

La menata è che così come è non soddisfa ne chi scrive, men che meno chi legge.

Jekyll FTW

author: Mauro Servienti | posted @ Friday, January 12, 2018 8:12 AM | Feedback (0)

CQRS e molteplici modelli in lettura


specchi

Quando ci aspettiamo di generare più di un modello in lettura a fronte di una singola modifica le cose diventano un filino più complesse di quelle che abbiamo descritto fino ad ora.

Il commento di Fabio centra appieno uno dei problemi:

image

Supponiamo uno scenario del tipo:

  1. Cerco un cliente in anagrafica
  2. Non lo trovo tra i risultati
  3. Pigio il pulsante “Nuova anagrafica cliente”
  4. Creo il cliente
  5. Torno ai risultati della ricerca

Il punto [5] è quello interessante, il modello in lettura che ci serve in quello scenario è quello specifico dei risultati della ricerca. Quello che viene generato, ad esempio, per la vista in lettura di una singola anagrafica non va bene.

Siccome lato back-end è difficile sapere quale sia il flusso che sta seguendo l’utente, quello che siamo costretti a fare è notificare il client della creazione di tutti i modelli in lettura possibili dato un aggregato che è stato modificato. In questo modo il client, conscio dello stato, può decidere quando l’operazione asincrona è effettivamente completata, per l’utente che la sta eseguendo.

La cosa risulta essere ancora più complessa, e sfocia nello sbagliato secondo la mia esperienza, se uno o più dei modelli che abbiamo bisogno di generare vive in un contesto diverso da quello in cui è avvenuta la modifica. Questo tipicamente succede quando scegliamo, seconda scelta sbagliata a mio modo di vedere, di veicolare gli eventi verso i denormalizzatori come messaggi su una coda. Che è anche relativo ad uno dei falsi miti di cui ho parlato tempo fa.

Appena decidiamo di mettere un evento di dominio, che ha due caratteristiche essenziali:

  • è interno al contesto
  • è ricco, o fat come si suol dire

su una coda corriamo il rischio che chiunque possa sottoscriversi a quell’evento, guidandoci inevitabilmente verso un bel monolite distribuito. La soluzione, all’apparente necessità di modelli in lettura che provengono dalla stessa fonte in contesti diversi è, come abbiamo già detto, ViewModel composition.

Quello della ricerca di informazioni resta sempre un nodo aperto, soprattutto in un sistema distribuito. Ne parleremo.

author: Mauro Servienti | posted @ Wednesday, January 10, 2018 4:27 PM | Feedback (0)

iPad Pro, il miglior acquisto degli ultimi anni


2010_mavericks_competition

A febbraio 2015 comperavo un iPad Mini, che ancor oggi fa il suo sporco lavoro anche se le prestazioni cominciano a subire i segni del tempo. Nel tempo è passato da mero strumento per leggere blog/notizie prima di colazione a vero e proprio strumento lavorativo. Posta che per me è anche uno degli strumenti di pianificazione della giornata, issue su GitHub, ticket di supporto, calendari, etc. Ci ho scritto anche parecchi dei post che trovate su queste pagine.

Visto l’uso che ne facevo le dimensioni cominciavano ad essere un problema, 7” sono un gran comodi in mobilità, ma diventano un limite se ad esempio dovete scrivere tanto. La tastiera a video è piccola e quelle esterne trovano il tempo il che trovano.

Un paio di mesi fa ho deciso di aggiornare la mia dotazione di serie e prendere un iPad Pro, quello “piccolo” da 10”.

Mai acquisto fu migliore

Non posso essere che pienamente soddisfatto. Ho acquistato anche la Smart Keyboard, e in tutta sincerità l’accoppiata delle due cose non mi fa in nessun modo sentire la mancanza del notebook che praticamente non uso più. In ufficio ho un desktop, e data l’estrema flessibilità della mia giornata, mi capita spesso di iniziare la giornata lavorativa sul tavolo della cucina, magari prima della piscina. A meno che non debba per forza scrivere codice, cosa che posso sempre rimandare di un paio d’ore, riesco a fare tutto dall’iPad. iPad che all’occorrenza posso anche trasformare in un secondo schermo. Infine dato che la workstation in ufficio è sempre accesa nella peggiore delle ipotesi mi collego in remote desktop e faccio quello che serve.

Più per curiosità che per reale necessità ho acquistato anche la “penna”. Al momento non so cosa farmene, ci sono molte applicazioni ben fatte per prendere appunti e per pianificare in stile agenda, ma ora come ora la carta le batte ancora tutte secondo me. Pian piano cercherò di capire cosa ci posso fare di utile.

author: Mauro Servienti | posted @ Monday, January 8, 2018 2:10 PM | Feedback (0)

CQRS e modello in lettura: quali alternative abbiamo?


puzzle

Qualcuno potrebbe giustamente obiettare che ogni volta che abbiamo a che fare con HTTP, essendo un protocollo disconnesso, abbiamo uno scenario che ha problematiche simili a quello asincrono che abbiamo descritto. Aggiungo io che ogni volta che abbiamo a che fare con uno sistema che non usa lock pessimistici in lettura abbiamo a che fare con uno scenario simile.

In realtà le problematiche sono due, molto diverse tra loro, ma entrambe da comprendere e maneggiare con cura e consapevolezza.

Concorrenza ottimistica

Lo scenario a prescindere da come viene generato il modello in lettura è:

  1. richiesta HTTP in GET
  2. i dati vengono letti dal db
  3. la connessione viene chiusa
  4. un oggetto serializzato viene ritornato al client

In tutti i casi al punto [3] i dati che abbiamo in mano sono vecchi, e per definizione sbagliati. Ergo per essere certi che l’utente non modifichi roba che già qualcun’altro ha modificato dobbiamo introdurre il concetto di versione dei dati, ad esempio un banale campo RowVersion nella tabella:

  1. richiesta HTTP in GET
  2. i dati vengono letti dal DB
    • insieme alla loro versione
  3. la connessione viene chiusa
  4. un oggetto serializzato viene ritornato al client
    • insieme alla versione
  5. Il client a questo punto modifica i dati
  6. in POST rimanda
    • i dati modificati
    • la versione originale
  7. Il server in fase di scrittura verifica che la versione sia uguale a quella che sta cercando di modificare

Funziona, non è per nulla complesso e mi aspetto che sia già così. Introduce ovviamente un interessante problema di UX, perché l’utente che ha davanti una bella form con tanti dati ne modifica un po’, salva e quando il salvataggio fallisce e dobbiamo trovare un modo furbo e semplice per far capire all’utente:

  1. perché il salvataggio è fallito
  2. quali sono i dati in conflitto
  3. permettergli di vedere la nuova versione dei dati in conflitto
  4. non perdere le sue modifiche pendenti

Che, in soldoni, equivale a consentire all’utente di risolvere un conflitto durante una merge. Tutto tranne che semplice sia dal punto UX che tecnico.

Conversazione asincrona

Qui le cose si fanno un filino più complesse. Se non siete in uno scenario stile fire & forget, ma avete la necessità di saper quando il processo di modifica dei dati è completo, dato che la verità per l’utente è il modello in lettura avete bisogno di sapere quando il modello asincrono è stato aggiornato. Il giro normale è:

  1. POST per scrivere i dati
  2. scrittura dell’aggregato
  3. “notifica” asincrona verso il denormalizzatore
  4. denormalizzazione del modello/i in lettura

A questo punto l’inghippo è che al punto [3] la connessione HTTP ha ritornato al client un bel 202, quindi il client non sa più nulla. Avete due strade:

  • ammazzare in polling il server per capire quando il modello in lettura ha la versione che vi aspettate abbia: il che però comporta anche che il client conosca la strategia di generazione delle versioni
  • aspettare una notifica dal server: ma come fa il server a sapere che deve notificare un determinato client? Non lo sa.

Abbiamo bisogno quindi di tener traccia di quella che potremmo definire una sorta di conversazione asincrona:

  1. POST per scrivere i dati
    • il client appende al post, ad esempio in un header, un GUID che rappresenta l’ID della conversazione
  2. scrittura dell’aggregato
  3. notifica asincrona verso il denormalizzatore (parliamo dopo del trasporto)
    • portando con se l’ID della conversazione
  4. denormalizzazione del modello/i in lettura
    • portando con se l’ID della conversazione
  5. notifica ai client che la conversazione con ID tal dei tali è completata, uno dei client sarà contento gli altri se ne fregheranno
    • il tutto può essere fatto con svariate strategie con SignalR, ad esempio.

La chiave di tutto sta qui:

il client appende al post, ad esempio in un header, un GUID che rappresenta l’ID della conversazione

Deve essere il client a gestire l’ID della conversazione, perché non vogliamo la spiacevole situazione:

  1. POST per scrivere i dati 
  2. Il server risponde con 202 e l’ID della conversazione

Il client non riceve mai la risposta HTTP e di conseguenza non conosce l’ID della conversazione e perde la possibilità di sapere cosa e quando succederà.

Quindi?

Mentre la gestione della concorrenza ottimistica è essenziale in qualsiasi scenario, la conversazione è necessaria solo ed esclusivamente se il modello in lettura viene generato in maniera asincrona.

Non usate CQRS con il modello in lettura asincrono

Il dottore non ci ha prescritto che il modello in lettura debba essere asincrono, tutti i database (documentali e non) supportano in qualche modo il concetto di proiezione (ad esempio le viste in un DB relazionale). Le proiezioni sono un perfetto modo per implementare il modello in lettura.

Se non avete milioni di utenti concorrenti e contemporanei e le viste sono lente, la vostra soluzione non è un modello in lettura asincrono, ma probabilmente il design del modello ha un po’ di problemi. Inoltre se vi ritrovata ad avere la necessità di costruire un modello in lettura che sia la summa di più aggregati che magari provengono da bounded context diversi, la soluzione non è un modello in lettura asincrono ne men che meno una proiezione generata con join che fanno i salti mortali carpiati. Forse è il caso che:

Per capirci:

  • scrivo attraverso una stored procedure
  • leggo da una vista

è una validissima implementazione di CQRS, semplice probabilmente e ridotta all’ossa ma valida.

Non scala? E devo scalare

Molto bene. Se siete certi che è tutto giusto e avete bisogno di più potenza di fuoco allora vada per la versione asincrona, consci che:

  • la complessità costa
  • la UX deve digerire la nuova complessità
  • la UX di conseguenza costa

Quindi prima di dire che dovete per forza scalare io tornerei ad analizzare quello che abbiamo alla ricerca di colossali problemi di performance, e nuovamente alla ricerca degli errori nella definizione dei boundary che spesso sono la sorgente di tanti mali.

CQRS è proprio in casi come questo che dimostra tutte le sue potenzialità. Avendo modelli diversi per canali con compiti diversi semplifica di molto l’evoluzione, anche infrastrutturale e/o tecnologica.

author: Mauro Servienti | posted @ Thursday, January 4, 2018 10:45 AM | Feedback (4)

Usare un iPad come secondo schermo


2018-01-02 14.59.31

Se avete due device Windows potete fare mirroring del display, o anche estensione, usando il secondo device come schermo esterno. La cosa è fattibile anche usando un iPad, nel mio caso un iPad Pro. È sufficiente installare sull’iPad Duet Display, applicazione a pagamento (al momento della scrittura circa 10 euro) e la sua controparte “server”, nel mio caso per Windows.

Una volta connesso l’iPad (o anche un iPhone) via USB, basterà avviare l’applicazione installata sul PC e l’applicazione su iPad per far si che Windows veda l’iPad come un secondo schermo. Dall’applicazione è poi possibile controllare la risoluzione, i frame per secondo, e l’eventuale modalità di risparmio energetico.

I tempi di risposta sono notevoli, non mi aspettavo fosse così responsivo. C’è a seconda dell’applicazione un leggero lag, ma decisamente trascurabile. La cosa interessante è che il touch dell’iPad continua a funzionare, non solo siccome Duet Display sul device è a sua volta un’applicazione potete avere scenari misti come il seguente:

2018-01-02 15.09.31

In cui Chrome è sul secondo schermo Windows, mentre Twitter è l’app iPad in overlay. Non ho verificato ma presumo che una cosa simile si possa fare anche con un device Android.

Direi non male come setup multi schermo da viaggio.

author: Mauro Servienti | posted @ Tuesday, January 2, 2018 3:13 PM | Feedback (0)