Mi piacerebbe sapere quale dovrebbe essere la firma dei miei metodi in modo da gestire elegantemente diversi tipi di guasti .Prova [Risultato], IO [Risultato], O [Errore, Risultato], che dovrei usare alla fine
Questa domanda è in qualche modo il riassunto di molte domande che avevo già sulla gestione degli errori in Scala. Potete trovare alcune domande qui:
- Throwing exceptions in Scala, what is the "official rule"
- Either, Options and for comprehensions
- Either monadic operations
Per il momento, ho capito quanto segue:
- entrambi possono essere utilizzati come un risultato wrapper per una chiamata di metodo che potrebbe non riuscire
- Provare è un diritto biaised Sia in cui il fallimento è un'eccezione non fatale
- IO (scalaz) aiuta a costruire metodi puri che gestiscono le operazioni di IO
- Tutti e 3 sono facilmente utilizzabile in un di comprensione
- Tutti e 3 non sono facilmente miscelabile in una di comprensione a causa dei metodi di flatMap incompatibili
- in langages funzionali che di solito non generare eccezioni a meno che non sono fatali
- ci dovrebbe generare eccezioni per davvero eccezionale condizioni. Credo che questo è l'approccio di Prova
- Creazione Throwables ha un costo delle prestazioni per la JVM e non è destinato ad essere utilizzato per controle flusso di business
strato Repository
Ora per favore considera che ho un UserRepository
. Lo UserRepository
memorizza gli utenti e definisce un metodo findById
. I seguenti guasti potrebbe accadere:
- Un guasto fatale (
OutOfMemoryError
) - fallimento Un IO perché il database non è accessibile/leggibile
Inoltre, l'utente poteva mancare, portando ad un Option[User]
risultato
Utilizzando un'implementazione JDBC del repository, SQL, eccezioni non fatali (violazione del vincolo o altro) possono essere generate in modo che possa essere opportuno utilizzare Try.
Dato che si tratta di operazioni IO, anche la monade IO ha senso se vogliamo funzioni pure.
Così il tipo di risultato potrebbe essere:
Try[Option[User]]
IO[Option[User]]
- qualcos'altro?
strato Servizio
Ora diamo introdurre un livello di business, UserService
, che fornisce un metodo che utilizza il updateUserName(id,newUserName)
definito in precedenza findById
del repository.
I seguenti errori possono accadere:
- Tutti i guasti repository propagate al livello di servizio
- errore di azienda: non è possibile aggiornare il nome utente di un utente che non esiste
- errore di business: il nuovo nome utente è troppo breve
Poi il tipo di risultato potrebbe essere:
Try[Either[BusinessError,User]]
IO[Either[BusinessError,User]]
- qualcos'altro?
BusinessError qui non è un Throwable perché non è un fallimento eccezionale.
Usando per-comprensioni
vorrei continuare a utilizzare per-comprensioni di combinare chiamate di metodo.
Non possiamo facilmente mescolare diverse monadi su una comprensione preliminare, quindi suppongo che dovrei avere una sorta di tipo uniforme di ritorno per tutte le mie operazioni, giusto?
Mi chiedo solo come riesci, nel tuo mondo reale applicazioni Scala, a continuare a usare le incomprensioni quando possono accadere diversi tipi di errori.
Per ora, per la comprensione funziona bene per me, utilizzando servizi e repository che restituiscono tutti Either[Error,Result]
ma tutti i diversi tipi di guasti si fondono insieme e diventa un po 'hacky per gestire questi errori.
Definite conversioni implicite tra diversi tipi di monadi per poter utilizzare le incomprensioni?
Definite le vostre monadi per gestire i guasti?
A proposito, forse userò un IO driver asincrono al più presto. Quindi credo che il mio tipo di ritorno potrebbe essere ancora più complicato: IO[Future[Either[BusinessError,User]]]
Qualsiasi consiglio è benvenuto perché io non so davvero cosa usare, mentre la mia applicazione non è fantasia: si tratta solo di un'API in cui Dovrei essere in grado di fare una distinzione tra errori di business che possono essere mostrati al lato client e errori tecnici. Cerco di trovare una soluzione elegante e pura.
Potresti postare un po 'di codice come hai finito per scrivere questo? Sono molto interessato perché ho in mente un modello simile. Le mie capacità di scalaz non sono quelle che vorrei che fossero ... Ho difficoltà a dare un senso a queste lezioni. – costa