Spettacolo!
Da un mesetto a questa parte sto lavorando ad un nuovo progetto che è nato quasi per caso.
In dicembre IL mio cliente storico si presenta e mi dice che avrebbero bisogno di una semplice applicazione per fare l’inventario di una delle loro attività al pubblico.
L’obiettivo è quello di avere uno strumento snello e semplice che permetta ad n operatori di lavorare insieme e funzioni senza fronzoli e soprattutto senza problemi dato che il tempo stimato per l’inventario è di 72h e l’attività commerciale non deve restare ferma di più. Al termine sarà onere di chi gestisce il sistema informativo di quell’attività sincronizzare i dati di inventario con l’infrastruttura esistente.
Quindi sintettizzando:
- pochi fronzoli;
- user frendly spintissimo;
- ciclo di vita brevissimo (72h);
- Tempo disponibile per la realizzazione 5gg, l’inventario sarebbe inizato la settimana dopo;
- disegno il mio modello fatto di interfacce;
- scrivo una suite di test che, grazie a un po’ di Stub e Mock, mi aiuta a capire che il modello sta insieme e mi piace;
- Implemento il modello e per la parte DAL/Repository scelgo Linq2Sql: produttività da paura;
- faccio una scelta azzardata e decido di utilizzare, per la UI, WPF (di cui so poco e nulla);
Siccome i primi 3 punti, grazie a un po’ di TDD ad una suite di test decente e ad un po’ di olio di gomito, li sbologno in 1 giorno e mezzo mi restano ancora 3 giorni abbondanti per la UI, su suggerimento di Corrado vado di Model-View-ViewModel e dopo un giorno di s*ado*nam*nti vari con xaml comincio a prenderci gusto e in perfetto orario dopo 3 giorni consegno la mia bella applicazione, facciamo l’inventario e tutto fila liscio come non mi sarei mai aspettato.
Un po’ di considerazioni sparse:
- WPF: Spettacolo! potenza e libertà infinite;
- Cider: a pain in the ass, non dico altro;
- Disabilitare al volo il designer e passare alla visualizzazione diretta dell xaml è un must;
- Alla fine addomesticare xaml, anche grazie al supporto notevole dell’IntelliSense di Visual Studio, non è poi così difficile;
- Scrivere una Window come si faceva nella preistoria con l’HTML (blocco note + markup + fervida immaginazione) non è poi molto difficile… certo il markup di xaml è un filino più esteso di quello di HTML… ;-)
- Expression Blend: molto utile, ma non fondamentale secondo me, diventa utile quando devi fare cose che l’immaginazione fa fatica a capire cosa/come saranno… o effettivamente quando cominci ad avere a che fare con animazioni, template, styling e tutte quelle belle funzionalità avanzate di WPF ma se vi limitate ad un’interfaccia Windows Form Like non è vitale;
- Model-View-ViewModel: manna dal cielo. M-V-VM unito alla potenza enorme del databinding di WPF è semplicemente spettacolare, permette due cose importanti:
- Testing della logica della UI: ci tengo a sottolineare della logica perchè se poi mi dimentico di mettere in binding un command con un elemento della UI non è che ci possa fare molto… è vero si può fare il testing della UI/View stessa ma io sono ancora scettico e secondo me il gioco non vale la candela almeno non ancora perchè gli strumenti non sono ancora maturi;
- Separation of Concern: rimpiazzare completamente il look&feel dell’applicazione, o meglio ancora farlo fare ad altri è sempre più un gioco da ragazzi… more on this later ;-)
Decidiamo allora, con solo 24h alla riapertua ufficiale, fortunatamente è festa, di investire sul prodottino che abbiamo usato per fare l’inventario e fare il possibile per rendere operativi gli operatori con le funzionalità indespensabili.
Spettacolo 2° atto.
- Avendo fatto uso massiccio di un framework di IoC diventa molto facile introdurre nel modello nuovi servizi e nuove entità;
- Essendoci una discreta batteria di test il cambiamento massiccio viene affrontato con una discreta sicurezza;
- L’uso di M-V-VM dimostra la sua potenza spettacolare perchè il refactoring della UI per passare dalla UI a senso unico ad una multi purpose è veramente facile, quasi disarmante;
Spettacolo 3° atto.
A questo punto il problema è che l’applicazione, che era nata con un unico scopo, deve diventare un gestionale, si… mono prodotto, ma… con tutti i crismi. Non solo l’inghippo vero e proprio è che praticamente siamo, nostro malgrado, in produzione in un’attività aperta al pubblico dove non è proprio semplice dire “ooops” abbiamo sbagliato dobbiamo fermarci un attimo… perchè non abbiamo uno stage di test. Stimolante :-D
Tutto ciò mi conferma che IoC/DI sono la flessibilità in assoluto introdurre nuovi servizi/entità cambiare le relazioni e le “dipendenze” è decisamente facile.
Il problema a cui mi sono trovato di fronte è però stato, e lo è tutt’ora perchè siamo in continuo divenire, lato presentation perchè la filosofia generale che ho seguito, Separation of Concern, rende abbastanza complesso l’approccio alla UI. Vediamo un esempio chiarificatore:
Il modello M-V-VM molto semplicemente mette un attore, il ViewModel, tra il modello e la view, questo attore ha una dipenedenza anche dagli eventuali servizi e li sfrutta per dialogare e/o manipolare il modello. Quel diagramma sembra semplice ma se cominciamo a pensare ad un’applicazione reale in cui probabilmente c’è più di una finestra la cosa si complica un filino ma comunque resta abbastanza semplice perchè ci basta introdurre un servizio di navigazione (INavigationService) che conosce la struttura dell’applicazione, le modalità di navigazione etc etc..
Ma…, perchè c’è sempre un ma…il bello del nostro lavoro :-D, complichiamoci ancora un po’ la vita e pensiamo ad un’applicazione veramente reale, una che abbiamo sottoledita tutti i giorni: Visual Studio.
La UI è decisamente complessa e le “regole” di M-V-VM ci dicono che ogni parte (teniamo a mente il termine “region”) della UI dovrebbe avere un corrispondente ViewModel ma qesto ci mette un po’ in crisi perchè le varie parti della UI/ViewModel molto probabilmente hanno bisogno di comunicare tra di loro… e qui siamo un po’ in croce perchè un “errore” che potremmo essere portati a fare, io l’ho fatto, è questo:
Il modello puzza già di suo ma nonostante tutto funziona, il problema però è grosso e si rende evidente al primo refactoring della UI. Una delle cose veramente potenti di Model-View-ViewModel è che rende totalmente indipendenti il look & feel dell’applicazione dalla logica su cio quel look & feel insiste. Per capirci: il ViewModel espone un “SaveCommand” e per lui è del tutto irrilevante di come la UI decida di presentare la funzionalità all’utente. Un esempio chiarificatore sta proprio nella UI di Visual Studio, il comando “Save All” appartiene alla finestra principale di VS ma quel comando si occupa di salvare “documenti” che non stanno, dal punto di vista logico, nella finestra principale se adottiamo una gerarchia di ViewModel (come nel diagramma di prima) risolviamo ma rendiamo dipendenti i “documenti” dalla finestra principale perchè la finestra principale deve conoscere l’esistenza dei documenti per poter invocare il comando “Save”. Diventa a questo punto evidente che se spostiamo i documenti siamo obbligati ad informare la finestra principale pena la pedita di funzionalità… male molto male.
Se sopra tutto ciò ci mettiamo la velleità di avere un sistema estendibile via add-in/package allora crolla proprio tutto molto alla svelta.
Soluzioni naturalmente ce ne sono, anche di già pronte, come ad esempio Caliburn e PRISM ma entrambe sono decisamente complesse e mi privano della mia irrefrenabile necessità di capire, quindi prima di tutto devo trovare la soluzione da me poi valuteremo se adottare una soluzione “boxed”.
Dato per assodato che M-V-VM non si tocca adesso abbiamo ancora 2 problemi da risolvere:
- Comunicazione tra i ViewModel: non potendo avere una gerarchia di ViewModel, perchè è troppo fragile, e dovendo quindi tener separti nettamente i ruoli abbiamo il problema di come far comunicare i vari moduli (aka Module) dell’applicazione;
- Flessibilità della UI: una UI complessa come quella di Visual Studio è composta da parti (Region) che sono molto flessibili e difficilmente gestibili con un semplice NavigationService;
La cosa è stata brillantemente, si me la tiro :-D, realizzando un semplice message broker basato sul modello publisher/subscriber, che è poi la tecnica, anche se con funzionalità decisamente più complesse, che usano i due blasonati framework che ho citato.
Ogni ViewModel ha (o può avere) una dipendenza da un servizio, grazie IoC!!, di borkering IMessageBroker e può usarlo per “postare”, IMessageBroker.Post
Anche per stavolta vi ho tediato abbastanza… :-D, avrei un’altra montagna di cose da dire anche molto tecniche, sarà per la prossima volta. Ci tengo però ha sottolineare che ho imparato qualcosa di nuovo, oltre alle novità squisitamente tecniche: fai quello che serve (punto), frena il tuo ego :-D
Io adoro questo lavoro!
.m