Pattern MVP ed Asp.Net – Prima parte

Lascia un commento

La complessità delle interfacce grafiche, sia in applicazioni Client/Server che Web Based, è costantemente in aumento e quindi nel tempo sono stati proposti diversi strumenti per facilitarne lo sviluppo come l’approccio RAD (Rapid Application Development) e l’introduzione di widget e controlli sempre più complessi e con potenti meccanismi di databinding dichiarativo. Ovviamente tali facility, come ho gia affermato in altre occasioni,  hanno spostato l’attenzione del programmatore sempre più sulla configurazione che sullo sviluppo vero e proprio (in questo caso del layer di presentazione) portando da un lato ad un aumento della produttività iniziale ma dall’altro allo sviluppo di applicazioni monolitiche difficilmente testabili in ambiente isolato e di conseguenza difficilmente estendibili senza incorrere nella prolificazione di bug di riflessione (stiamo parlando dunque di applicazioni difficilmente manutenibili).

Fortunatamente esistono diversi pattern architetturali che tentano di risolvere questo tipo di problematiche. Negli ultimi anni è il pattern MVC (Model View Contoller – Model2) ad essere sotto i riflettori come scelta vincente in tutti quei casi in cui si voglia sviluppare una GUI (Graphic User Interface) fortemente disaccoppiata dalle logiche di business. In effetti MVC è un’elegante soluzione che assolve splendidamente a tale problema, ma in alcuni contesti tecnologici (vedi l’utilizzo di ASP.Net Web Form) che non offrono un supporto nativo a tale pattern “potrebbe” non essere conveniente prendersi l’onere di implementare tutta l’infrastruttura necessaria per la sua implementazione. In questi casi il Pattern MVP è una soluzione da tenere assolutamente in considerazione ;)

Il Pattern MVP

Il pattern MVP (Model View Presenter) risale all’anno 1979 ed il suo nome originario era Thing Model View Editor (coniato dalla Taligent), nel tempo poi evoluto grazie soprattutto a Martin Fowler che ne ha sviluppato due diverse implementazioni Supervising Presenter e Passive View. La soluzione proposta prevede il disaccoppiamento totale della View dalle logiche di manipolazione del Modello tramite l’introduzione di un componente, il Presenter, che funga da intermediario e da coordinatore in risposta alle interazioni con l’utente. Ma vediamo nel dettaglio gli attori coinvolti:

  • View (visualizza i dati contenuti nel model e raccoglie gli input dell’utente)
  • Model (rappresenta il dominio di busines ed incapsula lo stato dell’applicazione)
  • Presenter (interagisce con il model in base alle richieste ricevute dalla view)
Schema di interazione – MVP Supervising Controller
In questo tipo di implementazione la view conosce il modello e generalemente è connessa ad esso tramite un meccanismo di data binding dichiarativo che permette l’aggiornamento dei dati da visualizzare (in situazioni complesse dove il data bindig dichiarativo non è sufficiente a garantire tale l’aggiornamento è necessario l’intervento del presenter).
  • L’utente interagisce in qualche modo con la View;
  • La View notifica al Presenter dell’interazione;
  • Il Presenter opera sul Model eventualmente modificandone lo stato in rispetto all’interazione notificata dalla View;
  • La View viene aggiornata in base ai nuovi dati esposti dal Model tramite un meccanismo di data binding;
  • Il Presenter, se presenti, aggiorna i dati della view che non possono essere agganciati a quest’ultima tramite data binding dichiarativo;

Schema di interazione – MVP Passive View

In questo caso la view non conosce il modello (non vi è quindi alcuna dipendenza tra la View ed il Modello) ed il presenter è l’unico responsabile dell’aggiornamento dei dati visualizzati.

  • L’utente interagisce in qualche modo con la View;
  • La View notifica al Presenter dell’interazione;
  • Il Presenter opera sul Model eventualmente modificandone lo stato in rispetto all’interazione notificata dalla View;
  • Il Presenter aggiorna la View in base ai nuovi dati esposti dal Model;

PRINCE2 – Il Business Case – II parte

Lascia un commento

Nella metodologia PRINCE2 il Business Case viene sviluppato durante la fase iniziale di un progetto come evoluzione del Project Brief (documento iniziale che definisce in modo sommario gli scopi, i costi, le tempistiche e le tolleranze creato nella fase di avvio del progetto a valle di un Mandato di Progetto), dal Piano di Progetto e dal Registro dei Rischi . E’ ovvio che nella fase iniziale del progetto il Business Case risulta essere ancora un’entità basata su informazioni presunte quindi lo stesso sarà corretto e riveduto ciclicamente durante tutta la durata del progetto per valutare che la giustificazione commerciale dello stesso resti tale.

Il responsabile del Business Case è l’EXECUTIVE che, facendo parte del team di gestione del progetto, ha la responsabilità di assicurare la creazione e l’approvazione dello stesso (la creazione del BC può comunque essere delegata ad altri membri del team che abbiano le competenze necessarie per poter assolvere a tale compito).

Il Business Case viene quindi:

  • Sviluppato tenendo in considerazione tutte le informazioni in proprio possesso sulle quali poter prendere decisioni in merito al progetto.
  • Verificato continuamente durante tutto il ciclo di vita del progetto per comprendere se la gistificazione commerciale dello stesso sia ancora valida o meno.
  • Manutenuto ovvero ciclicamente aggiornato con un consuntivo sui costi e sui benefici ottenuti sul periodo appena passato e preventivati per quello immediatamente successivo.
  • Confermato o meno successivamente alla valutazione delle consuntivazioni effettuate nel tempo.

Contenuto del Business Case

Come già detto più volte il Business Case descrive le motivazioni per le quali è conveniente intraprendere il progetto in relazione a Costi, Rischi e Benefici previsti e generalmente consta di:

  • Motivazioni per le quali è necessario realizzare il progetto.
  • Opzioni per l’aziendaovvero enumera e motiva le diverse posizioni che l’azienda può assumere in merito ad una questione.
    • Non Agire: l’azienda può decidere che non sia conveniente intraprendere alcuna azione relativamente ad una questione.
    • Agire al minimo: l’azienda può decidere che sia conveniente intraprendere un’azione relativamente ad una questione entro determinati limiti.
    • Agire in qualche modo: l’azienda può decidere in base ad una serie di valutazioni variabili in che modo agire in merito alla questione.
  • Benefici Previsti insieme di tutti i benefici ritenuti conseguibili in seguito alla realizzazione dei prodotti finali del progetto.
  • Controbenefici Previsti insieme di tutti i controbenefici ritenuti possibili durane o a seguito della realizzazione dei prodotti finali del progetto.
  • Tempistiche
    • Periodo di sostenimento costi.
    • Periodo di analisi.
    • Periodo necessario per lo svolgimento di tutte le attività per ogni pacchetto di lavoro.
    • Periodo …
  • Costi di progetto, di manutenzione, …
  • Valutazione dell’investimento ovvero un confronto dettagliato tra i costi ed i benefici previsti.
  • Rischi Principali ovvero una sintesi di tutti i rischi per il progetto.

L’approccio delle aziende alla tecnologia .Net

2 commenti

E’ sempre più facile trovare in rete tantissimi articoli sulle differenze tra la tecnologia .Net e altre tecnologie ritenute di fascia  Enterprise presenti sul mercato, ma ancora più frequenti sono quelli relativi alle diatribe tra i programmatori legati alle diverse piattaforme.
Per quanto mi riguarda non ho nessuna intenzione di esprimere il mio punto di vista sulla questione, per tre motivazioni:

  1. Non credo si possa generalizzare e semplificare questo discorso in poche rige di testo
  2. Svolgo attività di progettazione e sviluppo su tecnologie Microsoft principalmente .Net (rischierei di essere considerato di parte)
  3. Non ha senso scrivere un articolo su tale questione in attesa che diventi l’ennesima inutile guerra a colpi di commenti tra programmatori

Vorrei rivolgere invece la mia attenzione, magari con il vostro aiuto in termini di commenti a questo post, nell’analizzare il punto di vista che le aziende hanno su tale questione e come questa influenzi negativamente le attività degli addetti ai lavori.

Durante la mia esperienza professionale ho collaborato in diverse realtà informatiche e ciò che mi ha sempre lasciato perplesso è stato l’approccio, che nella maggior parte dei casi, viene utilizzato nella costruzione dei team di sviluppo per progetti legati alle diverse tecnologie (ovviamente mi riferisco a progetti di una certa dimensione) per non parlare poi delle suddivisione delle attività e dei tempi ritenuti sufficienti per la realizzazione dei prodotti finali (PRINCE2 ®).
Estremizzando la questione, e rispetto a quelle che sono state fino ad oggi la maggior parte delle mie esperienze, si potrebbe riassumere la questione come segue:

Le fugure “riconosciute” in un progetto Enterprise, indipendentemente dalla numerosità dei diversi ruoli, sono in genere

  1. Project Manager
  2. Project Officer
  3. IT Architect (Disegna e definisce la struttura dei sistemi informativi)
  4. Analisti Sr/Jr (Definizione degli obiettivi tecnici, progettazione della struttura della base dati, specifiche per il programmatore, ecc..)
  5. Sviluppatore Front-End Sr/Jr (Responsabile dello sviluppo per delle componenti per l’acquisizione dei dati di input e la presentazione di quelli in output)
  6. Sviluppatore Back-End Sr/Jr (Responsabile dello sviluppo della logica di business sui dati acquisiti)
  7. Specialista (Eventuale specialista di un particolare prodotto meno conosciuto dal resto del team)
  8. System integrator (Cura l’armonizzazione di sottosistemi di diversa natura e/o di diversi fornitori)
  9. Database Administrator (Progettazione fisica e della manutenzione del Data Base, delle utenze e delle funzioni dirette di gestione)
  10. Sistemista (Fornisce assistenza al team di sviluppo sull’utilizzo ottimale del software di base)
  11. Tester (disegno del piano del test, esecuzione dei casi di test e report dei risultati, interfacciamento con team di sviluppo)

Le fugure “riconosciute” in un progetto .Net, indipendentemente dalla numerosità dei diversi ruoli, sono in genere

  1. Project Manager
  2. Analista Programmatore Sr/Jr
  3. Programmatore Sr/Jr

Nel secondo caso ho omesso le responsabilità delle diverse figure in quanto sarebbe solo un’inutile provocazione specificarle :)

Tutto ciò mi ha portato  a riflettere sul fatto che moltissime aziende informatiche non riconoscono ancora la complessità e la completezza che oggi la tecnologia .Net offre senza nulla togliere alle altre.

Come ho già analizzato in un’altra serie di articoli non si può certo negare che le piattaforme microsoft abbiano “mascherato” per lungo tempo una certa complessità di sviluppo ai programmatori con un ricchissimo arsenale di strumenti RAD mancanti in altre tecnologie e che per tale motivazione il “programmatore Microsoft Base” rispetto agli altri abbia spesso ignorato una parte delle nozioni tecniche e/o filosofiche per l’implementazione di applicazioni “ben strutturate” (OOP, OOD, DDD, SOLID, Design Patterns, ecc..).

Tutto ciò ovviamente oggi si paga in termini di “cattiva pubblicità”, non tanto per la tecnologia .Net in se (in quanto ci sono comunque tantissime realtà che pur rimanendo un minima parte, ne hanno riconoscono il valore facendone un ulteriore punto di forza) ma soprattutto per gli addetti ai lavori che nella maggior parte dei casi non riusciranno a lavorare adeguatamente per il raggiungimento degli obbiettivi richiesti dal progetto sui quali saranno allocati come figura di factotum vedendo denigrata la propria professionalità.

Purtroppo non si può nemmeno negare che trovare programmatori .Net che abbiano una certa consapevolezza di ciò che sono i principi base per un corretto disegno architetturale non è semplicissimo, per diverse motivazioni:

  1. L’ambiente di sviluppo .Net offre tantissime facility erroneamente considerate analoghe agli strumenti, della stessa tecnologia, ma che dovrebbero essere utilizzati per la produzione di prodotti di fascia più alta.
  2. La presenza di una moltitudine di certificazioni raggiunte con kit di preparazione di dubbia moralità professionale che abbassano enormemente il livello medio della categoria.
  3. Il mancato investimento nella professionalizzazione dei propri dipendenti da parte di molte aziende informatiche.
  4. La svendita di tale professionalità da parte elle aziende informatiche nei confronti degli acquirenti.
  5. La pubblicizzazione del concetto di .Net = “Utilizzo un tool per una produzione senza scrivere una riga di codice”.

PRINCE2 – Il Business Case – I parte

Lascia un commento

La fase di startup di un progetto, sia esso legato alla crescita aziendale o perché no a quella personale, è sempre preceduto da un’attenta analisi del contesto nel quale lo stesso sarà presumibilmente realizzato. In questa fase si individueranno dei costi di realizzazione (“costo zero” è pur sempre un costo), dei tempi di sviluppo, una certa percentuale dei rischi, dei benefici e/o dei controbenefici.

Ognuna di queste variabili, oltre a variare da progetto a progetto, è soggetta a variazioni anche nella realizzazione di uno stesso progetto, portando talvolta a considerare, in corso d’opera, che non sia più conveniente continuare nell’impresa (in quest’ultimo caso comunque non deve necessariamente significare che non siamo stati abbastanza bravi nel nostro operato, infatti ogni impresa è sempre calata in un contesto che non è statico ma che evolve nel tempo mutando in relazione con gli elementi che lo influenzano e contemporaneamente ne vengono influenzati). L’errore che può essere ingenuamente commesso durante la stesura di un piano di progetto è considerare l’analisi delle variabili succitate come un’operazione da fare una tantum per ottenere il benestare sul progetto, poiché tale analisi se ciclicamente riveduta è anche la sentinella di allarme da utilizzare per prevenire possibili ostacoli e spesso l’unica arma vincente per raddrizzare la rotta verso il raggiungimento degli obietti iniziali.

Nell’ambito della metodologia PRINCE2 viene identificato come BUSINESS CASE

La raccolta e l’organizzazione delle informazioni utili per determinare l’auspicabilità (rapporto tra costi/beneficii/rischi), la fattibilità (capacità di realizzazione dei prodotti richiesti) e la realizzabilità (capacità dei prodotti realizzati di portare i benefici aspettati) di un progetto.

Così come il contesto nel quale si decide di agire anche il BUSINESS CASE non è un’entità statica, al contrario quest’ultimo DEVE essere aggiornato costantemente con le informazioni relative ai costi sostenuti, ai rischi, alle opportunità ed ai benefici che si svilupperanno in corso d’opera in modo da poter essere sempre in grado di valutare lo stato dell’arte e prendere decisioni in merito alla continuità dell’impresa non a caso il Business Case è alla base di tutti i processi decisionali.

PRINCE2 – Il Business Case – II Parte

ITIL – IT Infrastructure Library

Lascia un commento

ITIL (IT Infrastructure Library) è un framework di best practice consigliate per garantire il miglioramento dei servizi e delle strutture coinvolte nei processi IT e che, a differenza di altri, non si presenta come un modello teorico ma pittosto come una raccolta di metodologie che hanno dimostrato “sul campo” di migliorare la qualità di tali servizi nonchè i mezzi necessari a supportarli nel tempo.

La prima versione del framework, al tempo non ancora conosciuta con questo nome, fu rilasciata verso la metà degli anni ’80 e nacque dalla richiesta dal Governo Britannico che, non considerando sufficientemente valido il livello qualitativo dei servizi IT erogati, incaricò la CCTA (Central Computer and Telecommunication Agency) oggi nota come Office of Government Commerce (OGC), per ottimizzare l’efficienza ed il costo delle risorse IT.

ITIL v1 è poi successivamente evoluto prima nella versione 2 (con la quale raggiunse l’approvazione dei più nel mondo IT) nei primi anni del 2000 e poi nella 3 nel 2007.

La v3 si basa su un approccio basato sull’intero Ciclo di Vita dei Servizi IT introducendo il concetto di Service Life Cycle differentemente dalla v2 strettamente focalizzata sui processi. Questa impostazione, porta il dipartimento IT a focalizzare la propria attenzione sul valore che i servizi portano al Business dell’azienda o in generale del committente.

I 5 Core Books sui quali è basata ITIL v3 sono sono suddivisi uno per ogni fase del ciclo di vita del servizio:

  • Service Strategy: ovvero la definizione della strategia IT rispetto al Business
  • Service Design: quindi la fase progettazione del servizio
  • Service Transition: erogazione del servizio
  • Service Operation: manutenzione e gestione del servizio
  • Continual Service Improvement: miglioramento continuo del servizio in tutte le fasi del ciclo di vita

Una cosa da tenere assolutamente in considerazione nell’utilizzo di ITIL è che lo stesso non è uno standard, ciò vuol dire che mantenere le linee guida proposte non vuol dire non poterle “adattare” alle proprie strutture organizzative.

Approfondimenti:
http://www.itil-italia.com/
http://it.wikipedia.org/wiki/ITIL
http://www.itsmfi.org/content/introductory-overview-itil-v3-pdf
http://www.isacaroma.it/pdf/080131/ITL-Renna-31.01.08.pdf

Minimizzare le dipendenze

Lascia un commento

Una delle problematiche principali che spesso impediscono la realizzazione di applicazioni modulari e facilmente estendibili è rappresentato dalle dipendenze esistenti tra i componenti che le costituiscono. Eliminare queste dipendenze vuol dire poter godere di innumerevoli vantaggi come la possibilità di effettuare test automatici ed avere un codice più incline al cambiamento. Negli ultimi anni, la marcata diffusione di framework come Spring, ha portato l’attenzione di un gran numero di sviluppatori su interessanti concetti quali la gestione dell’IoC (Inversion of Control), l’implementazione di tecniche relative alla AOP (Aspect Oriented Programming) e servizi di Service Locator Transparency che, se ben applicati, ci aiutano a minimizzare le dipendenze tra le entità di un sistema.

Ma cerchiamo di chiarire il concetto di dipendenza:

  1. “Una classe A dipende da una classe B quando: A eredita da B”
  2. “Una classe A dipende da una classe B quando: A crea un istanza e/o utilizza un istanza di B ”
  3. “Una classe A dipende da una classe C quando: B dipenda da C ed A dipende da B”

Inversion of Control (o IoC)
Solitamente nello scrivere applicazioni di una certa complessità spesso si finisce ad avere frequenti casi di dipendenza tra le classi di un Domain Model, questo accade perché, in generale, si rendono le classi stesse responsabili della propria inizializzazione e soprattutto nel costruttore, o in un metodo di inizializzazione preposto, si fa si che la classe istanzi tutto ciò di cui ha bisogno per funzionare correttamente. In parole povere è il codice stesso che ha il “controllo” di come vengono inizializzati gli oggetti. In progetti di elevata complessità tutto questo porta spesso ad avere diversi problemi in fase di refactory dell’architettura applicativa. Possiamo per esempio immaginare quei casi in cui, a fronte di nuove esigenze, si abbia la necessità di modificare il processo di inizializzazione di alcune entità del nostro modello, ovviamente ciò comporta il dover “mettere mano” al codice in tutti quei punti in cui queste vengono istanziate ed inizializzate. Per ovviare a tali problematiche si possono sfruttare dei meccanismi di inizializzazione configurabile, ed è proprio in questo ambito che l’Inversion of Control (IoC) trova il suo campo d’applicazione.

In generale non è detto che un oggetto sia a conoscenza del macro-contesto nel quale sarà utilizzato, ciò significa che un’entità dovrebbe saper comunicare con l’ambiente nel quale viene posta nel modo più generico possibile e potersi, quindi, considerare indipendente dal contesto applicativo corrente. A tal proposito viene introdotto il concetto di iniettore (talvolta chiamato anche assemblatore) ovvero l’entità che dovrebbe occuparsi, di “preparare i componenti già pronti all’uso” su richiesta di un qualsiasi consumer in modo da svincolare quest’ultimo dall’onere di istanziare ed inizializzare le sue dipendenze (leggi classi utilizzate). In secondo luogo bisogna dire che il consumer stesso, essendo un eventuale candidato all’utilizzo da parte di altre entità, non dovrebbe doversi preoccupare neanche della sua inizializzazione.

Progettare un iniettore è un’operazione che in prima analisi più sembrare un operazione alquanto semplice, ma bisognerebbe considerare con attenzione che sviluppare un iniettore troppo semplice potrebbe comportare come unico risultato lo spostamento delle problematiche succitate in un’altro punto dell’applicazione. Un iniettore per avere senso di esistere deve garantire un elevato grado di flessibilità ottenibile con un altrettanto elevato grado di configurabilità.

La Dependency Injection
La Dependency Injection è un design pattern che tenta di risolvere i problemi di dipendenza tra entità di un modello di domino attuando politiche di Inversion Of Control. Con la Dependency Injection una classe o un sistema non è responsabile dell’inizializzazione delle proprie dipendenze ma prevede la presenza di un iniettore che “inietti” tali dipendenze direttamente negli oggetti gestiti.

L’iniettore deve offrire un meccanismo di configurazione utilizzato per la definizione degli oggetti conosciuti e di come questi siano correlati tra di loro; alla richiesta di un dato oggetto l’iniettore controlla quali altre classi sono ad esso collegate, le crea, e le inietta al suo interno prima di rendere l’oggetto disponibile. Arrivati a questo punto, potremmo quasi considerare le classi del nostro domain model come dei dispensatori di servizi e l’iniettore come un Service Locator particolare in quanto oltre ad individuare le classi svolge anche il compito non banale di inizializzarle e renderle pronte all’uso.

NOTE:

In generale per minimizzare le dipendenze tra oggetti è necessario che questi dialoghino tra loro tramite interfacce (o classi astratte per i linguaggi che le supportano), in questo modo l’oggetto dipendente (un oggetto A ad esempio) può regredire al grado di semplice utilizzatore senza doversi più preoccupare di conoscere le modalità con le quali la sua dipendenza (intesa come un oggetto B dal quale dipende A) viene instanziata e inizializzata. Potremmo dire  che l’oggetto A, a questo punto, sa che dialogherà con qualcuno (che conosce come IB e non come B, ovvero conosce la sua interfaccia e non una sua speciale implementazione) e che questo qualcuno saprà come portare a termine determinate operazioni ma senza sapere questo qualcuno chi sia (A conosce cosa c’è da fare ma non chi e come lo farà). L’oggetto B, quindi, sarà costretto ad implementare un interfaccia (un comportamento da garantire, IB appunto).

Una dependency è un modo diverso di chiamare le variabili di un classe, i suoi campi, o se si preferisce la variabili di istanza che dipendono da tipi non appartenenti al core standard del linguaggio utilizzato.

Il procedimento di injection è l’inizializzazione di una variabile (della dependency), ciò avviene quando all’esterno della classe che contiene la dependency  si passa la dependency stessa già inizializzata che può avvenire tramite costruttore, tramite proprietà (interfaccia) o tramite metodo setter.

IoC Container
L’importanza dell’implementazione sempre crescente dei meccannismi di IoC e di DI in progetti reali ha portato negli ultimi anni allo sviluppo di svariati framework per semplificarne l’utilizzo (un famoso esempio ne è Srping), tali framework sono considerati come IoC Container ovvero una sorta di repository dove a fronte di un’adeguata configurazione possono essere referenziati dei mapping sui tipi i nmodo che il framework possa su richiesta dei consumer scovare le dipendenze instanziarle e iniettarle al chiamante. Definendo quindi delle interfacce comportamentali, ed implementandole nelle nostre classi concrete, risulta possibile accoppiare le classi a run-time senza più porsi il problema di conoscere le entità concrete a compile-time.

S.O.L.I.D. – Solidi principi per la scrittura di buon codice

Lascia un commento

I principi di seguito elencati, ed in parte spiegati, dovrebbero aiutare il programmatore, laddove non arriva l’esperienza, ad ottenere un codice di qualità che mantenga una forte coesione ed un basso accoppiamento tra le entità del sistema. Non devono però diventare un dogma, ma uno strumento da conoscere e da utilizzare a seconda degli obiettivi e dei requisiti applicativi.

Single Responsibility Principle (SRP)
Ogni classe deve essere disegnata per svolgere bene un solo compito, avere una sola responsabilità, in pratica una classe deve avere un solo motivo per cambiare. Seguire questo principio porta a diminuire per quanto possibile l’accoppiamento tra le entità coinvolte in uno o più processo. Uno dei modi più semplici per scrivere classi da modificare veramente di rado consiste nello scrivere classi che svolgono una sola azione. In questo modo, la classe dovrà essere modificata soltanto se sarà necessario modificare l’azione per la quale è stata creata.

Open/Closed Principle (OCP)
Una classe deve essere aperta alle estensioni, ma chiusa alle modifiche. Dobbiamo quindi essere in grado di estendere il comportamento di una classe senza modificarne l’implementazione. Come? Facendo uso di classi astratte o interfacce, ovvero sfruttando il concetto di polimorfismo.

Liskov Substitution Principle (LSP)
Una funzione che utilizza un riferimento ad una classe base deve poter utilizzare al suo posto una qualsiasi delle classi derivate senza conoscerne l’implementazione. In pratica non dobbiamo modificare in alcun modo il comportamento di una classe base in una derivata. Particolare attenzione dovrebbe infatti essere rivolta ai concetti pre-condizioni e le post-condizioni relative al ciclo di vita di una classe e delle classi da essa ereditate. In generale non si può pensare di scrivere una classe base partendo da determinate precondizioni e pensare di specializzare da essa una classe che ne presenti altre di tutt’altra forma. In alcuni contesti quindi si dovrebbe valutare se preferire dove possibile la composizione all’ereditarietà, ponendosi ogni volta la fatidica domanda IS A or HAS A?

Interface Segregation Principle (ISP)
Una classe non deve implementare una interfaccia che non usa o che usa parzialmente. Molte volte si deve preferire avere più interfacce con una sola funzionalità che averne una unica ma che si occupa di troppe cose. Il motivo? Una classe è influenzata dal cambiamento di una interfaccia anche se non la usa.

Dependency Inversion Principle (DIP)
Questo principio si basa sul concetto che una classe di un alto livello non deve dipendere dall’implementazione di classi o entità di un livello inferiore. In pratica per raggiungere tale scopo si dovrebbero progettare le classi pensando alle interfacce e non alle implementazioni. Questo porta ad avere non solo un basso accoppiamento tra i livelli dell’architettura, ma automaticamente a poter sostituire l’implementazione di un livello inferiore senza pregiudicare il funzionamento di quelli superiori.

Da un modello procedurale ad un modello ad oggetti – Seconda Parte

Lascia un commento

Leggi la prima parte dell’articolo…

Nel 1991 la Microsoft propose sul mercato quello che da li a poco divenne uno degli strumenti di sviluppo RAD più famosi al mondo: Visual Basic 1.0 per Windows (dato l’enorme successo nel 1992 fu sviluppata dalla casa di Redmond anche l’alterego per DOS dove l’interfaccia utilizzava i caratteri ASCII estesi per simulare l’apparenza di una interfaccia grafica).

Indubbiamente Visual Basic spopolò per tutta una serie di caratteristiche che pur avendo poco da offrire in termini di OOD al tempo risultavano estremamente interessanti:

  1. Programmazione event driven;
  2. Semplicità d’uso (non utilizza formalità di punteggiatura tipica di quasi tutti gli altri linguaggi);
  3. Ambiente di lavoro RAD per la realizzazione interfacce GUI anche complesse (complessità che risultava trasparente al programmatore);
  4. Pratico accesso alle basi dati tramite oggetti e widzard visuali.
  5. Creazione di controlli ActiveX con il linguaggio stesso.

Non a caso ho utilizzato l’espressione “al tempo risultavano estremamente interessanti”, e mi spiego:
Il mondo dell’informatica, e tutto ciò che ruota intorno ad essa, è passata di moda in moda.. di necessità in necessità.. infatti mentre un tempo il GURU di turno era il programmatore capace di spremere fino all’ultimo bit di un calcolatore sviluppando algoritmi estremamente performanti agli inizi degli anni novanta era la Rapidità di Sviluppo a catturare l’attenzione delle aziende, rapidità di sviluppo dove il RAD la faceva da padrone.

I linguaggi e gli ambienti e le metodologie di programmazione RAD, Visual Basic in primis ed a seguire tutti i suoi simili, per un lungo periodo hanno avuto il predominio su quelli che oggi definiamo più evoluti ma che al tempo erano comunque già presenti sul mercato e che sembravano non esserlo affatto, perché? Il saggio Design Patterns: Elements of Reusable Object-Oriented Software, della Gang of Four, vede la sua prima edizione nel 1995 eppure proprio nell’agosto di quell’anno Visual Basic 4.0 era uno dei linguaggi di programmazione più usati per lo sviluppo di applicativi gestionali di considerevole complessità. Come si spiega tutto ciò?

Perché il mercato non era pronto!
Le software house non avevano richieste abbastanza esigenti da giustificare l’investimento su tecnologie più costose in termini di risorse e di tempo. Oggi dove le applicazioni crescono in dimensioni e complessità in maniera esponenziale dall’oggi al domani, dovendo comunque garantire continuità di servizio, la richiesta di manutenibilità e di scalabilità sostituisce nella maggior parte dei casi quella di “rapidità di sviluppo”.
Potremmo dire a questo punto che il RAD ha concluso ormai il suo ciclo di vita (almeno in parte in quanto tutt’oggi la maggior parte degli ambienti di sviluppo offrono un’ottima integrazione di strumenti RAD e Controllo totale), che ha svolto a dovere e per parecchio tempo il suo compito.

Volendo analizzare le motivazioni per le quali tali tecnologie hanno raggiunto un limite abbastanza forte potremmo utilizzare tre concetti chiave per descrivere le principali problematiche dei software basati su ambienti RAD: fragilità, immobilità e viscosità.

Fragilità del software
Gli applicativi scritti con linguaggi come Visual Basic, almeno fino alla versione 6.0, generalente sono scritti secondo l’approccio conosciuto come “Spaghetti Code” .

E’ chiaro che in un codice sorgente scritto secondo lo stile dello spaghetti code, anche se di sole poche migliaia di righe di codice, sia estremamente complesso, pur avendo individuato con chiarezze le cause di eventuali malfunzionamenti, agire senza poter essere sicuri al 100% di non apportare danno in un altro punto dell’applicazione stessa.

Immobilità del software
Un importante fattore da considerare è che senza un’ottimizzazione puntuale delle responsabilità funzionali, cosa che risulta difficilmente ottenibile con la programmazione RAD, la riusabilità del codice e l’estendibilità dello stesso risulta più complessa e talvolta estremamente limitata.

Viscosità
Per via della fragilità del codice lo sviluppatore è costretto, nella maggior parte dei casi relativi ad azioni di manutenzione o adeguamento, a dover patchare il proprio codice e spesso in più punti per porre rimedio alle inaspettate conseguenze che le stesse patche portano in altri punti dell’applicazione e tutto ciò rende sempre più difficoltoso modificare parti di codice nel sorgente al passare del tempo.

Le motivazioni di ciò sono da ricondurre alla dipendenza che gli attori di un sistema (sia esso un macro o un micro sistema) hanno tra di loro. E’ indubbio che non esiste un sistema software nel quale non esistano dipendenze tra gli oggetti collaboratori ma con le tecniche di OOP si può tentare di disaccoppiare quanto più possibile i ruoli e le responsabilità di tali elementi mantenendo il giusto compromesso tra coesione ed accoppiamento senza finire però nel paradosso (come nel paradosso di Zenone “Achille e la Tartaruga” si potrebbe finire, nel tentativo estremo di disaccoppiamento, a non raggiungere mai il giusto compromesso tra Coesione ed Accoppiamento).

OOP ma allora è realmente “tutta salute”?
Indubbiamente la Object Oriented Programming (si presuppone che il lettore conosca i principi base della OOP) offre tutta una serie di vantaggi rispetto alla programmazione procedurale e quella RAD per risolvere per quanto possibile le problematiche precedentemente esposte, ma anche quest’ultima non è esente da insidie che possono passare inosservate.

Talvolta alcune feature offerte dalla OOP possano rivelarsi essere delle armi a doppio taglio. L’ereditarietà per esempio, uno dei tre pilastri cardine della programmazione ad oggetti, se mal controllata può portare anch’essa a situazioni scomode ed inaspettate (una qualunque classe specializzata per esempio può essere vista come una “classe fragile” in quanto dipendente dalle modifiche che trasparentemente un altro programmatore potrebbe apportare, magari a valle di una successiva e frettolosa refactory, semplicemente intervenendo sulla classe base compromettendo il funzionamento della classe specializzata). A tal proposito esistono una serie di solidi principi (S.O.L.I.D. principles) da seguire durante la progettazione per la produzione di “buon codice” orientato alla manutenibilità, estendibilità, scalabilità e stabilità.

Da un modello procedurale ad un modello ad oggetti – Prima parte

Lascia un commento

La crescita esponenziale delle aziende e la conseguente necessità di automatizzare processi sempre più critici e complessi ha nel tempo portato gli sviluppatori ad abbandonare il modello di programmazione procedurale in favore di quello orientato agli oggetti che, seppur già presente fin dagli anni novanta, non aveva ottenuto al tempo un seguito cospicuo.

In quegli anni potremmo dire con simpatica che lo sviluppatore era portato a snobbare la Object Oriented Programming (OOP) poiché la complessità relativamente contenuta delle applicazioni prodotte in quel periodo non giustificava l’investimento, in termini di tempo e di risorse, che avrebbe richiesto l’utilizzo di tale modello di sviluppo. Tutto ciò sarà sicuramente opinabile da chi può permettersi di affrontare lo sviluppo software con un fare principalmente filosofico (Architetti, Ingegneri, ecc..) ma la questione è più spinosa di quanto potrebbe sembrare in quanto le aziende informatiche (purtroppo) non vivono di sola filosofia, ed ogni investimento in termini di tempo e risorse va giustificato con un rientro economico che a fine progetto faccia quadrare i bilanci aziendali.

Tutt’oggi molti professionisti ancora non riconoscono i benefici portati dall’utilizzo della OOP, spesso si sente dire o si legge su forums e blogs di carattere informatico:

  • OOP = Meno codice da scrivere
  • OOP = Meno manutenzione
  • OOP = Meno…

e poi nella pratica i conti non tornano.. ci si ritrova a fine progetto con un quantitativo maggiore di codice rispetto ad uno stesso progetto scritto con un approccio procedurale e con la stessa necessità di dover intervenire per manutenere ed, eventualmente su richiesta estendere il prodotto.

Ma allora dov’è il guadagno?
Innanzitutto sarebbe da chiarire una volta per tutte che, per quanto se ne dica, scrivere software secondo il modello della OOP “non vuol dire assolutamente scrivere meno codice, tutt’altro!” ma il sensibile aumento del numero di righe di codice di un progetto viene giustificato dalla necessità di disaccoppiare gli attori e le rispettive responsabilità che gli stessi assolvono in un processo indipendentemente da quanto complesso esso sia. Più codice quindi, ma necessario per separare e successivamente assegnare ruoli e funzionalità in un realtà dove gli stessi attori possono essere utilizzati per assolvere ad uno o più compiti ben definiti anche in sistemi e/o sottosistemi differenti (stiamo parlando di separazione delle responsabilità e successivo riutilizzo di codice esistente).

Per quanto riguarda la manutenzione: non esiste ad oggi alcuna applicazione che non necessiti di manutenzione. Secondo alcune statistiche, presenti in rete, si stima che la maggior parte degli sviluppatori siano impegnati per il 65-70%≈ della loro carriera professionale su interventi di manutenzione e sviluppi evolutivi piuttosto che di progettazione di software ex-novo e questo comporta la necessità di avere del codice facilmente mantenibile ed estendibile.

La naturale organizzazione del codice scritto secondo l’approccio Object Oriented Design (OOD) dovrebbe poter dare al programmatore la possibilità di modificare una determinata e molto più ristretta porzione di codice con la conseguenza di propagare tale modifica in tutti i punti del sistema in cui quella funzionalità viene utilizzata (Manutenibilità) .

Un uso intelligente dei concetti della OOP, soprattutto se accoppiato allo sviluppo basato su diversi layer applicativi, porta ad un altro vantaggio che diviene sempre più una necessità su applicativi di grandi dimensioni la: testabilità. La divisione delle competenze, infatti, semplifica il test puntuale delle funzionalità di un componente (anche in questo caso il termine semplifica non è da confondere con il termine velocizza, vedi il tempo che portano via gli unit test). In generale infatti (lo vedremo più avanti) le classi di un Object Model dovrebbero essere, passatemi il termine, quanto più striminzite (specifiche) possibile sia per una questione di precisa definizione del ruolo degli oggetti nel sistema sia per aumentare la riusabilità e la testabilità degli stessi.

Leggi la seconda parte dell’articolo…

Follow

Get every new post delivered to your Inbox.