Mokabyte

Dal 1996, architetture, metodologie, sviluppo software

  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti
  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti

Nel numero:

142 luglio
, anno 2009

Il programmatore e le sue Api

XVI parte: La gestione delle eccezioni nelle applicazioni enterprise

Alfredo Larotonda
Alfredo Larotonda

Alfredo Larotonda, laureato in Ingegneria Elettronica, lavora da diversi anni nel settore IT. Dal 1999 si occupa di Java ed in particolare dello sviluppo di applicazioni web J2EE. Dopo diverse esperienze di disegno e sviluppo di applicazioni web per il mercato finanziario e industriale, si occupa ora in particolare di aspetti architetturali per progetti rivolti al mercato della pubblica amministrazione. È Sun Certified Enterprise Architect (SCEA) e ha inoltre conseguito le certificazioni SCJP, SCWCD 1.3, SCWCD 1.4, SCBCD.

MokaByte

Il programmatore e le sue Api

XVI parte: La gestione delle eccezioni nelle applicazioni enterprise

Picture of Alfredo Larotonda

Alfredo Larotonda

  • Questo articolo parla di: Architetture dei sistemi, Programmazione & Linguaggi

In questo articolo affrontiamo l‘argomento della gestione delle eccezioni nelle applicazioni enterprise: ovviamente non si tratta di un articolo di base sulle eccezioni, ma piuttosto di un tentativo di fornire spunti e suggerimenti per un corretto approccio al problema.

Introduzione

In questo articolo affrontiamo un argomento spesso piuttosto trascurato nella realizzazione di applicazioni Java enterprise n-layered: la gestione delle eccezioni. Molto dello sforzo di definizione architetturale e di disegno delle applicazioni è dedicato alla scelta dell’architettura applicativa, delle tecnologie e dei framework da utilizzare nei diversi layer e nella definizione dei vari componenti che implementano i diversi livelli applicativi. Anche gli articoli precedenti della serie si sono soffermati su questi aspetti. Molto spesso però non si affronta con la medesima attenzione l’argomento della gestione delle eccezioni che viene trascurato in fase di disegno e lasciato un po’ al caso e alla sensibilità del singolo sviluppatore. Di seguito cercheremo quindi di fornire alcuni spunti sia per far comprendere come la gestione delle eccezioni sia un aspetto molto importante per la qualità del software da realizzare, sia per suggerire alcune modalità pratiche di gestione.

Aspetti di base

Non è nello scopo del presente articolo affrontare in dettaglio i concetti di base della gestione delle eccezioni in Java, che dovrebbero essere ben conosciuti da qualsiasi progettista o sviluppatore con un minimo di esperienza del linguaggio. In maniera estremamente sintetica, è sufficiente ricordare che le eccezioni sono il meccanismo con il quale in Java viene segnalata una situazione di errore verificatasi nell’esecuzione del codice. Le eccezioni in Java si dividono in due categorie principali, le checked e le unchecked.
Le eccezioni di tipo checked devono essere obbligatoriamente gestite dove vengono generate, nel senso che il codice nel quale una eccezione checked può essere generata deve essere inserito in un blocco try/catch, oppure l’eccezione deve essere rilanciata al metodo chiamante mediante la dichiarazione della clausola throws nel metodo.
Le eccezioni di tipo unchecked invece non devono essere gestite obbligatoriamente in un blocco try/catch e non necessitano della definizione della clausola throws nel metodo in cui vengono generate. In [1] è possibile trovare tutti i dettagli necessari alla conoscenza dei meccanismi che il linguaggio fornisce per la gestione delle eccezioni.

Affrontando il problema della gestione delle eccezioni per una applicazione a n-livelli, non solo bisogna conoscere questi meccanismi di base ma bisogna anche pensare a una gestione che sia coerente con i principi di base che portano alla costruzione di una applicazione ben strutturata.
Unire questi principi architetturali con le regole di base per la gestione corretta delle eccezioni non è sempre così facile ed immediato e le soluzioni possono essere diverse in base all’approccio che si preferisce da un punto di vista architetturale.
Il principio di base che secondo me però è sempre valido è che, se non è possibile fare nulla per gestire in qualche modo una eccezione… allora è meglio non gestirla per nulla. Non è raro vedere codice applicativo contenente un mare di righe per la gestione di eccezioni assolutamente irrecuperabili. In genere nei libri sul linguaggio Java si consiglia di utilizzare eccezioni checked per tutte le situazioni in qualche modo recuperabili ed eccezioni unchecked per le altre. In realtà la distinzione non è così netta e spesso non viene sottolineato come da un punto di vista funzionale i due tipi di eccezioni sono assolutamente equivalenti nel senso che anche una eccezione unchecked può essere gestita.
Il mio consiglio in questo caso è di utilizzare sempre eccezioni unchecked e di decidere se gestirle o meno a seconda della situazione. Le eccezioni unchecked consentono di scrivere codice privo di inutili blocchi try/catch e permettono la definizione di metodi nei quali non è necessario dichiarare una marea di eccezioni, cosa molto utile nella definizione di interfacce poiche’ preserva la struttura del metodo in caso di cambiamento di implementazione.
Si potrebbe giustamente obiettare che, nella scrittura di un’applicazione, abbiamo sempre a che fare con librerie di terze parti e che quindi potremmo sempre essere nella situazione di utilizzare un metodo di una classe scritta da qualcun altro che rilancia una eccezione di tipo checked. In questo caso non abbiamo scelta, ovviamente, ma possiamo ricorrere alla tecnica del wrapping della eccezione per fare in modo da non dover inserire blocchi try/catch o clausole throws.

Effettuare il wrapping di una eccezione significa semplicemente catturare una eccezione e incapsularla in un’altra di differente tipo come nel semplice codice seguente:

try{
    object.method();
} catch (Exception checkedException) {
    throw new MyException("exception", checkedException);
}

In questo caso l’eccezione checked rilanciata dal metodo method dell’oggetto object viene wrappata in una eccezione unchecked MyException che viene rilanciata dal metodo. Il metodo chiamante non è costretto ad inserire blocchi try/catch o clausole throws, ma può decidere se gestire o meno l’eccezione.

Applicazioni a n livelli

Arrivati a questo punto della serie sappiamo cosa si intenda per applicazione a n-livelli e dovremmo avere ben chiari i principi architetturali alla base di una buona progettazione di applicazioni enterprise complesse. Uno di questi principi sui quali ci siamo soffermati spesso è quello della separazione dei livelli applicativi.
Abbiamo sempre insistito sul fatto che una buona applicazione dovrebbe essere strutturata in modo che un layer venga esposto al layer adiacente esclusivamente mediante interfacce , ovvero il layer adiacente deve essere assolutamente indipendente dall’implementazione dell’altro layer e non deve avere alcuna conseguenza dal cambiamento di quest’ultimo. Questo principio dovrebbe rimanere valido anche nel caso delle eccezioni anche se a volte ciò contrasta con la semplicità di scrittura dell’applicazione. Detto in maniera generale ogni layer dovrebbe gestire le proprie eccezioni al suo interno, e non propagarle agli altri strati applicativi.
Un approccio quindi potrebbe essere il seguente, facendo sempre l’ipotesi di una applicazione a tre livelli presentation-service-persistance implementata con Spring, Hibernate e un web framework come Struts o JSF.

Lo strato di persistenza ingloba in wrapping le sue eccezioni in una DAOException che è l’unica che comunica al layer di business:

public Object executeMethod() throws DAOException {
    try {
        HibernateTemplate hTemplate = getHibernateTemplate();
        hTemplate.executeMethod();
    } catch (DataAccessException dae) {
        throw new DAOException("executeMethod() " + dae.getMessage(), dae);
    }
    return object;
}

Il layer di business segue lo stesso approccio facendo il wrapping delle eccezioni in una ServiceException:

public Object executeMethod() throws ServicesException
{
    Object object = null;
    try {
        object = dao. executeMethod();
    } catch (DAOException de) {
        throw new ServicesException("Exception ", de);
    }
    return object;
}

Ovviamente questa è una semplificazione in quanto in ogni layer si potrebbe definire una gerarchia di eccezioni per consentire di distinguere tra le varie situazioni di errore. In questo caso DAOException e ServiceException sarebbero le eccezioni in cima alla gerarchia di ciascun layer, e avrebbero una serie di altre eccezioni gerarchicamente definite sotto di esse.
A questo punto l’eccezione dopo aver viaggiato tra i vari layer arriva al layer di presentation che deve obbligatoriamente gestirla.
Infatti la cosa da evitare sempre è di mostrare all’utente uno stacktrace conseguente a una eccezione, sia perche’ l’utente non è in grado di comprendere l’informazione visualizzata, sia perche’ questo dà l’impressione di una applicazione poco solida e di scarsa qualità.
A livello di presentation la scelta migliore è gestire in un punto univoco mediante un’opportuna classe handler tutte le eccezioni presentando all’utente opportuni messaggi di errore.
In Struts questo è molto semplice in quanto può essere fatto esternamente al codice sfruttando gli handler forniti dal framework. In [2] è presentato un esempio di gestione dichiarativa delle eccezioni con Struts.

In base a quanto detto quindi si definisce per ogni layer una gerarchia di eccezioni di tipo unchecked e le eccezioni vengono gestite a seconda delle situazioni nel singolo layer ma per l’esterno vengono definite interfacce che dichiarano solo l’eccezione base della gerarchia. Ciò consente di arricchire in ogni layer la gestione delle eccezioni a piacimento, wrappando anche eccezioni checked rilanciate da classi di librerie di terze parti utilizzate nel layer. Il layer adiacente in ogni caso è indipendente dalla aggiunta di nuove eccezioni nel layer sottostante o dall’utilizzo di librerie che dichiarano eccezioni checked ma può in ogni caso gestirle, se ne ha in qualche modo bisogno, effettuando l’unwrapping.
In questo modo, le interfacce dei vari layer rimangono stabili: non è necessario inserire inutili blocchi try/catch ne’ effettuare l’unwrapping delle eccezioni quando non è necessario gestirle. Questo approccio è valido sia quando si ha il controllo di tutti i layer applicativi, sia quando il layer applicativo deve essere utilizzato da un layer sviluppato da altri.

Riassumendo: siamo partiti da due semplici principi, uno riguardante le eccezioni e uno riguardante le applicazioni ad n-livelli:

  1. È inutile gestire una eccezione per la quale non possiamo fare nulla
  2. I livelli applicativi devono essere indipendenti l’uno dall’altro e comunicare solo attraverso interfacce

A partire da questi due semplici principi e tenendo presente i concetti di base della gestione delle eccezioni in Java abbiamo suggerito l’utilizzo di eccezioni unchecked e della tecnica del wrapping delle eccezioni checked.

Da ciò abbiamo enunciato gli elementi di base per la gestione delle eccezioni nei layer applicativi:

  1. Definire una gerarchia di eccezioni unckeched in ogni layer
  2. Wrappare con una eccezione della gerarchia le eccezioni checked generate nel layer
  3. Gestire all’interno del layer quando ciò è necessario le eccezioni
  4. Propagare al layer adiacente l’eccezione base della gerarchia definendola nell’interfaccia
  5. Gestire l’eccezione in un altro layer se necessario effettuando l’unwrapping della stessa
  6. Gestire sempre le eccezioni nel layer di presentation con un opportuno handler non propagandola mai all’utente finale

Questi sono principi di base che possono fungere da guida nella implementazione della gestione delle eccezioni in una applicazione ad n-livelli. Chiaramente questo non è l’unico approccio ma è in linea con i principi architetturali seguiti fino ad ora nello sviluppo della serie.

Va sempre tenuto presente che saranno sempre presenti situazioni particolari che richiedono soluzioni ad-hoc che magari si allontanano molto da quanto detto. Però, enunciare principi di base da seguire è sempre una cosa utile e necessaria per un corretto approccio alla realizzazione di applicazioni complesse.

Conclusioni

Nel presente articolo abbiamo trattato l’argomento della gestione delle eccezioni nelle applicazioni Java enterprise a n-livelli. Non abbiamo trattato nello specifico la gestione delle eccezioni di singoli framework sia perche’ sarebbe impossibile in un solo articolo sia perche’ abbiamo preferito enunciare principi di base validi indipendentemente dalla implementazione scelta per un singolo layer applicativo. L’articolo può essere preso come spunto per linee guida da seguire: l’enunciazione di questi principi è vista nell’ottica di mantenere fede alla regola di base della separazione dei livelli applicativi senza però trascurare un approccio semplice e non ridondante nella trattazione delle eccezioni.

Riferimenti

[1] AA.VV., “The Java Tutorials. Trail: Essential Classes. Exceptions”, 1995-2008, Sun Microsystems
http://java.sun.com/docs/books/tutorial/essential/exceptions/index.html
[2] Alfredo Larotonda, “Sviluppare applicazioni J2EE con Jakarta Struts – VI parte: la gestione delle eccezioni”, MokaByte 86, Giugno 2004

 

 

 

Alfredo Larotonda
Alfredo Larotonda

Alfredo Larotonda, laureato in Ingegneria Elettronica, lavora da diversi anni nel settore IT. Dal 1999 si occupa di Java ed in particolare dello sviluppo di applicazioni web J2EE. Dopo diverse esperienze di disegno e sviluppo di applicazioni web per il mercato finanziario e industriale, si occupa ora in particolare di aspetti architetturali per progetti rivolti al mercato della pubblica amministrazione. È Sun Certified Enterprise Architect (SCEA) e ha inoltre conseguito le certificazioni SCJP, SCWCD 1.3, SCWCD 1.4, SCBCD.

Facebook
Twitter
LinkedIn
Picture of Alfredo Larotonda

Alfredo Larotonda

Alfredo Larotonda, laureato in Ingegneria Elettronica, lavora da diversi anni nel settore IT. Dal 1999 si occupa di Java ed in particolare dello sviluppo di applicazioni web J2EE. Dopo diverse esperienze di disegno e sviluppo di applicazioni web per il mercato finanziario e industriale, si occupa ora in particolare di aspetti architetturali per progetti rivolti al mercato della pubblica amministrazione. È Sun Certified Enterprise Architect (SCEA) e ha inoltre conseguito le certificazioni SCJP, SCWCD 1.3, SCWCD 1.4, SCBCD.
Tutti gli articoli
Nello stesso numero
Loading...

Strumenti di build e test con Groovy

III parte: Ancora su Gradle. Gestione delle dipendenze e build di progetti multimodulo

Interoperabilità tra applicazioni: un approccio orientato ai Web Service

I parte: SOA, Web Service e interoperabilità

Semantic Web. Esplorazione/visualizzazione di ontologie

I parte: Introduzione e analisi dei tool attuali

Web Beans

V parte: La gestione degli eventi

WebSphere in cluster

I parte: Sviluppo parallelo e ambienti di integrazione

Nella stessa serie
Loading...

Il programmatore e le sue API

XIX parte: Introduzione al test delle applicazioni enterprise

Il programmatore e le sue API

XX parte: realizzare la GUI web con GWT

Il programmatore e le sue API

XVIII parte: Sviluppare l‘interfaccia web con tecnologie RIA

Il programmatore e le sue API

XVII parte: Il logging corretto

Il programmatore e le sue api

XV parte: Integriamo il layer di presentazione realizzato con JSF

Il programmatore e le sue API

XIV parte: Il business service layer con Spring

Il programmatore e le sue API

XIII parte: Approfondiamo Spring

Il programmatore e le sue API

XII parte: Il business service layer con Spring

Il programmatore e le sue Api

XI parte: Considerazioni finali sulla persistenza

Il programmatore e le sue API

X parte: Ultime considerazioni sulla persistenza con Hibernate

Il programmatore e le sue API

IX parte: Ancora sul design della persistenza con Hibernate

Il programmatore e le sue api

VII parte: Ancora sull‘uso dei pattern nella architettura

Il programmatore e le sue API

VIII parte: Il design della persistenza con Hibernate

Il programmatore e le sue api

VI parte: L‘architettura del sistema

Il programmatore e le sue api

V parte: ancora sulla persistenza, due relazioni particolari

Il programmatore e le sue api

IV parte: Il design della persistenza

Il programmatore e le sue api

III parte: Si inizia a definire il datamodel

Il programmatore e le sue api

II parte: Impostare la fase di analisi

Il programmatore e le sue api

I parte: Lo startup di progetto

Mokabyte

MokaByte è una rivista online nata nel 1996, dedicata alla comunità degli sviluppatori java.
La rivista tratta di vari argomenti, tra cui architetture enterprise e integrazione, metodologie di sviluppo lean/agile e aspetti sociali e culturali del web.

Imola Informatica

MokaByte è un marchio registrato da:
Imola Informatica S.P.A.
Via Selice 66/a 40026 Imola (BO)
C.F. e Iscriz. Registro imprese BO 03351570373
P.I. 00614381200
Cap. Soc. euro 100.000,00 i.v.

Privacy | Cookie Policy

Contatti

Contattaci tramite la nostra pagina contatti, oppure scrivendo a redazione@mokabyte.it

Seguici sui social

Facebook Linkedin Rss
Imola Informatica
Mokabyte