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)

Quando la verità non è una sola: CQRS, consistenza eventuale, e utenti


illusion

Mi capita troppo spesso di osservare implementazioni di CQRS prese troppo alla leggera, con conseguenti (tanti tanti) buchi che fanno acqua da tutte le parti. Soprattutto quando, spesso senza che ve ne sia una vera necessità, l’implementazione comporta consistenza eventuale tra modello in scrittura e modello in lettura.

Quello che spesso osservo è un pastrocchio di concetti che tendono a fare di tutta l’erba un fascio e una soluzione che deve per forza portare con se concetti e pattern architetturali che nessun dottore ha mai detto debbano andare per forza insieme. Stanno bene insieme, ma nessuno ci obbliga a metterli insieme.

Troppo spesso osservo il seguente approccio

  • Che figata che è Event Sourcing, lo dovrò sicuramente usare
  • Lo userò per questo nuovo fiammante progetto di data entry
  • Costruisco degli aggregati che fungano da command processor e persistono solo eventi, sono un purista io, mia micio micio bau bau
  • Prendo questi eventi e li sparo su una coda con un bus, sono super figo
  • Scodo e con dei denormalizzatori costruisco il modello in lettura così ho anche una bellissima implementazione di CQRS, che è come il prezzemolo sta bene ovunque

Lontani da sta gente, stare bisogna. Lasciando perdere ogni considerazione in merito vorrei però concentrarmi su un problema singolo: consistenza eventuale, aggregati e modello in lettura.

A prescindere dall’esempio volutamente forzoso di cui sopra, quando si ha a che fare con sistemi distribuiti complessi la consistenza eventuale è spesso un male necessario.

L’ossimoro

Perché è un problema? Perché ci troviamo di fronte ad un problema architetturale da non sottovalutare: in DDD gli aggregati sono la fonte unica della verità (single source of truth). Orbene, appena introduciamo un modello in lettura asincrono, e di conseguenza eventualmente consistente introduciamo una dicotomia rognosa che dobbiamo per forza gestire, non possiamo ignorare.

Se l’aggregato è la fonte della verità per il sistema è altresì vero che il modello in lettura è la fonte della verità per l’utente.

La cosa si complica ulteriormente quando dato un singolo aggregato abbiamo più modelli in lettura che possono avere inconsistenze diverse in un dato momento t, con la conseguenza che l’utente potrebbe essere ulteriormente spiazzato.

Le complessità introdotte, sia a livello di user experience che a livello tecnologico non sono banali e devono essere valutate molto bene a fronte della decisione di adottare un modello asincrono. Come dicevo ci sono situazioni in cui è pressoché inevitabile, ma in tutte quelle in cui si può evitare io personalmente lo eviterei. Del resto non siamo né Amazon né Google ma troppo spesso siamo convinti che le loro soluzioni siano l’ideale anche per noi.

author: Mauro Servienti | posted @ Friday, December 29, 2017 2:19 PM | Feedback (0)

Utenti e sistemi


800px-Michelangelo_Merisi_da_Caravaggio_-_The_Cardsharps_-_WGA04083

Stamattina leggevo questo interessante post di Alessio Biancalana, e sebbene mi trovi d’accordo con le premesse non condivido le conclusioni e men che meno l’unico commento presente al momento della lettura.

UX e UI sono l’unica cosa che vedono

È indubbio che l’interfaccia utente sia l’unica cosa che un utente normale è in grado di percepire, ne consegue quindi che se UI e UX sono pietose per l’utente l’applicazione sarà pessima e poco utilizzabile, a prescindere dal dettaglio che sia efficace. Ci sono ovviamente, ad oggi, delle eccezioni a questa regola. Ma sono sempre meno e sono tipicamente ancora in quei settori dove nessuno ha dimostrato che si può fare di meglio.

La cosa sacrosanta che si evince dal post di Alessio è che noi, tecnici, come campione di riferimento siamo indubbiamente quello sbagliato.

Fretta

Ritengo invece frettolose le conclusioni, non è una questione, o meglio non solo, di prestazioni dei sistemi di back-end, ma soprattutto non è una questione tecnologica. Non sono cioè ne Rust ne Elixir la soluzione. Il tool o linguaggio di turno nelle mani di chi ha già fatto cose pessime non può che produrre cose pessime. Quindi dare in mano tool migliori a chi ha prodotto già schifezze non lo migliorerà di certo, anzi tenderà a peggiorarlo. Oltre all’incompetenza di fondo si aggiungerà anche la non conoscenza del tool.

L’educazione degli utenti

image

Io personalmente la escludo a priori. Non perché ritenga che sia impossibile piuttosto perché ritengo che se il sistema è ben fatto, non serva educare nessuno.

2 miliardi di persone usano Facebook tutti i giorni, senza il manuale delle istruzioni, senza educazione (anzi spesso ne hanno proprio poca). Nonostante tutto riescono a portare a termini task che con altri software non sarebbero in grado di portare a termine.

Quando qualcuno riesce a fare un filmato da un telefono, manipolarlo aggiungendo cazzate in overlay, e infine pubblicarlo su Facebook, ma non riesce ad allegare un documento ad un messaggio di posta elettronica, la colpa sarebbe dell’utente e le soluzioni Rust e Elixir?

UX e UI sono l’unica cosa che vedono

Se gli utenti possono vedere, e comprendere aggiungo io, solo UX e UI queste sono le cose su cui dobbiamo principalmente concertarci, il resto sarà una conseguenza. Quando lo UX Architect di turno ci dirà cosa vuole la rosa di soluzioni a disposizione si limiterà molto, portando architettura e tecnologia con se.

Ne consegue che se il team scelto conosce solo un tipo di martello, e magari lo sa usare pure male, ovviamente tutto il bel castello crolla ancora prima di essere costruito. Da questo, a mio modo di vedere, se ne deducono due cose:

  • lo studio UX va fatto prima di ogni cosa, è determinante per molte scelte che seguiranno
  • forse in maniera un po’ forzosa si potrebbe aggiungere che se un team conosce (il mio concetto di conosce, sia chiaro) Rust ed Elixir ha abbastanza cartucce da sparare, sicuramente più di un team che conosce solo VB6

E il budget? direte voi. È ovviamente una questione di budget, ma come dice mio suocero: se non avete i soldi state a casa vostra. Da un punto di vista tattico potrebbe aver senso consegnare qualcosa di scadente, da un punto di vista strategico forse anche no. Non portatemi come esempio le robe parastatali all’italiana, li le regole del gioco sono altre ;-)

author: Mauro Servienti | posted @ Wednesday, December 27, 2017 11:44 AM | Feedback (3)