Welcome

This is the generic homepage (aka Aggregate Blog) for a Subtext community website. It aggregates posts from every blog installed in this server. To modify this page, look for the Aggregate skin folder in the Skins directory.

To learn more about the application, check out the Subtext Project Website.

Powered By:
Powered by Subtext

Blog Stats

  • Blogs - 714
  • Posts - 31528
  • Articles - 310
  • Comments - 108121
  • Trackbacks - 226405

Bloggers (posts, last update)

Latest Posts

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

posted @ 2/23/2018 3:20 PM by Mauro Servienti

Vue.Js with ASP.NET Core MVC

posted @ 2/21/2018 9:17 AM by Alessandro Gervasoni

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.

posted @ 2/16/2018 4:17 PM by Mauro Servienti

Obfuscar

The Simplest .NET obfuscation tool. And it's free!


https://www.obfuscar.com

posted @ 2/8/2018 12:05 PM by Alessandro Gervasoni

MVC in ASP.NET Core

posted @ 2/4/2018 3:34 PM by Alessandro Gervasoni

UnQlite

An Embeddable NoSQL Database Engine
https://unqlite.org

posted @ 1/29/2018 3:00 PM by Alessandro Gervasoni

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

2018-01-16 14.27.01

Quelle manine!

A presto.

posted @ 1/26/2018 11:39 AM by Mauro Servienti

Npgsql

Npgsql is an open source ADO.NET Data Provider for PostgreSQL, it allows programs written in C#, Visual Basic, F# to access the PostgreSQL database server. It is implemented in 100% C# code, is free and is open source
http://www.npgsql.org

posted @ 1/24/2018 9:36 PM by Alessandro Gervasoni

Sabato 20 gennaio 2018 ci vediamo a Bologna per parlare di Serverless?

imageIl 2018 comincia alla grande, con una trasferta a Bologna dagli amici di Bologna Developer Zone per parlare di Azure Functions, Logic Apps e Event Grid.

Qui trovate tutti i dettagli e il link di iscrizione: https://www.meetup.com/it-IT/BolognaDeveloperZone/events/245285635/. L'evento pomeridiano terminerà poi, per chi si vuole fermare, con una cena tutti insieme!

L’idea è di capire come sfruttare al meglio questo paradigma negli scenari ottimali, integrandolo con il resto delle nostre soluzioni IaaS, PaaS, container-based, on-premise e ibride.

Cercheremo poi di capire il futuro di questo potentissimo strumento!

posted @ 1/18/2018 10:03 AM by Lorenzo Barbieri

c4model - model for software architecture

posted @ 1/17/2018 5:19 PM by Alessandro Gervasoni

Mockaroo - Random Data Generator

https://www.mockaroo.com

Need some mock data to test your app? Mockaroo lets you generate up to 1,000 rows of realistic test data in CSV, JSON, SQL, and Excel formats.

posted @ 1/17/2018 11:06 AM by Alessandro Gervasoni

Ramda

http://ramdajs.com/

A practical functional library for JavaScript programmers.

posted @ 1/15/2018 7:15 PM by Alessandro Gervasoni

Oggi sono di fretta ;-)

hurry-2119711_1280

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

posted @ 1/15/2018 9:17 AM by Mauro Servienti

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

posted @ 1/12/2018 8:12 AM by Mauro Servienti

What’s New in HTML 5.2

posted @ 1/10/2018 7:39 PM by Alessandro Gervasoni

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.

posted @ 1/10/2018 4:27 PM by Mauro Servienti

Alcuni link utili per creare automaticamente VM di terze parti dal Marketplace Azure

E’ un tema un po’ spinoso, e fino a poco tempo fa non completamente automatizzabile. Me lo segno che a oggi si fa ancora fatica a trovare questi link.

Per poter creare una VM di terze parti dal Marketplace di Azure da Powershell, CLI o SDK (REST o nativi, .NET, Java, etc…) bisogna aver precedentemente accettato la licenza. Fino a poco tempo fa questo era fattibile solo dal portale, creando a mano la prima VM o accettando esplicitamente la licenza: https://azure.microsoft.com/en-us/blog/working-with-marketplace-images-on-azure-resource-manager/.

Ora invece possiamo farlo anche tramite API REST (https://blogs.msdn.microsoft.com/arsen/2017/10/02/azure-marketplace-api-to-programmatically-review-and-accept-publisher-agreementeula/), PowerShell (https://docs.microsoft.com/en-us/powershell/module/azurerm.marketplaceordering/set-azurermmarketplaceterms?view=azurermps-5.1.1) o anche tramite SDK nativo per .NET (https://www.nuget.org/packages/Microsoft.Azure.Management.MarketplaceOrdering).

A questo punto possiamo elencare le VM disponibili, creare le risorse necessarie, accettare la licenza e creare la VM, il tutto completamente da codice. Il tutto anche da PowerShell e da Azure CLI.

Ricordatevi che il PurchasePlan è obbligatorio in caso di macchine terze, e che tutte le informazioni sono case sensitive e devono corrispondere a quelle dell'accettazione della licenza.

p.s. il tutto funziona anche da ARM template, basta accettare la licenza da PowerShell e indicare il Purchase Plan nel template ARM.

posted @ 1/8/2018 5:30 PM by Lorenzo Barbieri

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.

posted @ 1/8/2018 2:10 PM by Mauro Servienti

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.

posted @ 1/4/2018 10:45 AM by Mauro Servienti

UpUp - The Offline First Library

a tiny script that makes sure your site is always there for your users

https://www.talater.com/upup

posted @ 1/3/2018 11:16 AM by Alessandro Gervasoni

Latest Images

From miscellaneous
From miscellaneous
From miscellaneous
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini
From Immagini