Business logic: how do you return on application errors?

(note: post will be translated in English as soon as possible)

Oggi qui siamo alle prese con una decisione di design che non ci decidiamo a prendere :), ho parlato un po’ con il gruppo e con alcune vecchie conoscenze ma non ho ancora trovato una soluzione pienamente soddisfacente: cosi mi rivolgo a voi, magari avete consigli “sbloccanti”.

Normalmente nelle applicazioni che disegno cerco sempre, come molti, di disaccoppiare la logica di presentazione da quella di business: la user interface si occupa di interagire con l’utente, mantenendo lo stato conversazionale, mentre nella business logic troviamo il domain model con le logiche di business che si applicano ad esso.Attenzione: non stiamo parlando di applicazioni CRUD che si limitano ad usare un interfaccia utente per scrivere su DB, ma di programmi con un domain model articolato, che eseguono elaborazioni di una certa complessità una volta che la richiesta dell’operazione è stata inserita tramite una user interface (web, swing, xul che sia, non è interessante). Dovendo quindi disaccoppiare questi due strati tendo ad esporre dal lato business un’insieme di “servizi”: non pensate alla tecnologia, è semplicemente una scelta di design, che poi potrà essere implementata con dei POJO, dei web services, degli EJB, qualunque cosa ci venga in mente poi di ficcarci in mezzo.(proprio perchè la tecnologia è un mezzo, non un fine :D).

Avremo quindi dei servizi come questo: (scrivo in pseudo-java, ma potrei anche usare IDL)

// una delle interfacce della business logic
public interface MyService
{
   public void executeComputation(Slot slot, Computation compu)
   ;

   public Slot[] selectAvailableSlots(Range range)
  ;
}

(notate come stia esponendo una parte del domani model, ma questa è un’altra storia)

Essendo questa della business logic vera ci sono anche delle regole di business che devono essere verificate, e questo è possibile farlo solo a livello di business (certamente la presentation fa il suo lavoro per validare e scremare i dati ineriti, ma si limita a quello). Esiste quindi un’intera classe di errori che la business logic puo’ generare a causa della violazione delle business rules del momento, che non sono comunque verificabili in nessun modo a priori dalla presentazione (sia perché queste possono variare rapidamente sia perché mi piace che non ne sappia un cacchio!).

Come fare a ritornare queste condizioni di errore? Io finora ho individuato due macro-soluzioni:
a) utilizzare un’eccezione applicativa (aka BusinessRuleException) contenente l’errore
b) utilizzare un valore di ritorno contente sia il risultato sia l’eventuale errore

La soluzione (a) mi piace proprio poco. Utilizzare le eccezioni per modificare il controllo di flusso è da sempre, almeno per me, una vera schifezza e inoltre rende il codice assai poco leggibile. Le eccezioni devono secondo me rappresentare eventi di tipo appunto eccezionale (problemi sull’infrastruttura, ad esempio il DB si è disconnesso, non si riesce a contattare un servizio secondario, ecc.ecc) e come tali vanno gestite. Pertanto, pur essendo tanto attraente almeno superficialmente, la scarterei.

La soluzione (b) è secondo me la più naturale, d’altronde la violazione di una business rule è una cosa perfettamente naturale per la business logic, ma si porta dietro anch’essa un codice un po’ pasticciato. Non posso pensare di realizzare tante classi *Result differenti per gestire la varietà dei risultati forniti dalla business logic (nel caso in oggetto un metodo è void mentre l’altro ritorna un array) e pensandoci un po’ ho trovato questa soluzione tecnica, che ancora non mi convince del tutto: realizzare una classe Result con i generics e quindi modificare la firma dei metodi in modo che tornino questa. Il codice, tanto per chiarire, sarebbe questo:

// la classe che incapsula il risultato di una chiamata al business (value object)
public class Result {
   private F value;
   private Error error;

   public Result(F value) {
       this(value, Error.NONE);
   }

   public Result(F value, Error error) {
       this.value = value;
       this.error = error;
   }

   public F value() {
       return value;
   }

   public Error error() {
       return error;      }
}

L’interfaccia del servizio (di tutti i servizi) sono modificate in questo modo, ritornando un Result generico in ogni caso:

interface MyService
{
   public Result executeComputation(Slot slot, Computation compu)
   ;

   public Result<Slot[]> selectAvailableSlots(Range range)
   ;
}

Ok, fine dell’elucubrazione. Il punto è: cosa ne pensate? Io sto per muovermi su quest’ultima soluzione.

Advertisements

3 thoughts on “Business logic: how do you return on application errors?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s