Era un po’ di tempo che non mi divertivo così tanto a fare questo lavoro!
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;
Dopo una breve analisi la scelta è stata:
- 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);
I primi tre punti vanno via lisci, il quarto, sgomitando un bel po’ tra San Google e San Corrado, a cui va tutta la mia ammirazione per avermi supportato ma soprattutto sopportato…, va via altrettanto liscio… e voi direte ma che ce frega ma che ce importa!?!? adesso arriva il bello, pazienza ;-)
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 ;-)
A seguito dell’inventario quello che succede è che chi gestisce il sistema si “rifiuta” (il rifiuta è un termine un po’ troppo forte ed è una lunga storia con un sacco di buone ragioni, ma ci ha comunque colto un po’ alla sprovvista) di adoperarsi per l’integrazione dei dati dell’inventario… panico!
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;
In 16h realizziamo qualcosa di utilizzabile talmente ben riuscito che decidiamo di andare avanti…
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;
Vi dico subito che il secondo problema non l’ho ancora affrontato perchè non è tra le mie priorità, mentre il primo si è posto proprio qualche giorno fa proprio a seguito della necessità di fare un massiccio refactoring della UI ridistribuendo e rivoluzionando le funzionalità a disposizione.
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<T>( T message ), mentre un altro ViewModel può decidere di fare la subscription ad un determinato messaggio, IMessageBroker.Subscribe<T>( Object subscriber, Action<T> callback ), e attendere che qualcuno pubblichi qualcosa… semplice, funziona e funziona pure un gran bene disaccoppiando complemente i vari ViewModel e permettendoci di fare tutto il refactoring che vogliamo.
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