SlideShare una empresa de Scribd logo
1 de 27
Manejo de errores con typelevel.cats
El recorrido
● Error y Excepción.
● El excepcionalismo imperativo.
● Encapsular excepciones en Try.
● Errores como parte del dominio.
● Manejo de errores con Scala Either.
● Acumular errores con Validated.
● Reportar errores y aciertos con Ior.
● Conclusiones.
Error y Excepción
● Error: resultado no deseado de la evaluación de un programa.
● Excepción: condición excepcional del programa en tiempo de
ejecución.
El excepcionalismo imperativo
● Durante la evaluación de un método, si se encuentra un error se arroja
una excepción.
● Este paradigma puede tener su origen en:
○ Lenguajes imperativos sin un sistema de tipos robusto.
○ Considerando lo anterior, carencia de tipos de datos (datatypes) que
permitan manejar los errores.
● Se requiere try/catch para manejar los métodos que puedan arrojar
excepciones.
El dominio
case class Book(isbn: String, title: String, author: String, genre: Genre)
trait Genre extends Product with Serializable
object Genre {
case object Fiction extends Genre
case object ScienceFiction extends Genre
case object HistoricNovel extends Genre
case object InvalidGenre extends Genre
}
val theFountainhead = Book("ISBN: 978-1-4028-9462-6","The Fountainhead","Ayn Rand",Genre.Fiction)
val atlasShrugged = Book("ISBN-13 978-1-4028-9462-6","Atlas Shrugged","Ayn Rand",Genre.Fiction)
val theCountOfMontecristo = Book("ISBN-13 978-1-4028-9462","The Count Of Montecristo","Alexandre
Dumas",Genre.HistoricNovel)
val titlelessBook = Book("ISBN-13 978-1-4028-9462-6","","Unknown",Genre.InvalidGenre)
Un libro con isbn, título, autor y género.
El excepcionalismo imperativo
private def validateGenre(g: Genre): Unit =
if ( g == Genre.InvalidGenre ) throw new InvalidParameter("Book has invalid genre")
private def validateIsbn(isbn: String): Unit = isbn match {
case isbnRegex(all @ _*) => ()
case _ => throw new InvalidParameter("isbn has not a valid format")
}
private def validateTitle(title: String): Unit =
if (title.isEmpty || title == null) throw new InvalidParameter("title must not be empty")
private def validateAuthor(author: String): Unit =
if (author.isEmpty || author == null) throw new InvalidParameter("author must not be empty")
class InvalidParameter(message: String) extends Exception(message)
class EmptyBookList(message: String) extends Exception(message)
El excepcionalismo imperativo
def validateBook(book: Book): Book = {
validateGenre(book.genre)
validateIsbn(book.isbn)
validateTitle(book.title)
validateAuthor(book.author)
book
}
def validateBooks(books: List[Book]): List[Book] =
if (books == Nil) throw new EmptyBookList("Book list was empty")
else {
val booksBuffer = new ListBuffer[Book]
for (book <- books) {
try booksBuffer += validateBook(book) catch { case ex: Exception => println(s"Error $ex") }
}
booksBuffer.toList
}
Encapsulando excepciones con Try
● El tipo Try[A] es utilizado para manejar excepciones en métodos.
● Encapsula el resultado en dos subtipos: Success y Failure.
● Success contiene el resultado del método.
● Failure contiene la excepción arrojada.
● Nos permite usar for comprehension.
● Es fail fast en Failure.
Encapsulando excepciones con Try
private def validateGenre(g: Genre): Try[Genre] = Try {
g match {
case Genre.InvalidGenre => throw new InvalidParameter("Book has invalid genre")
case genre => genre
}
}
private def validateIsbn(isbn: String): Try[String] = Try {
isbn match {
case isbnRegex(all @ _*) => isbn
case _ => throw new InvalidParameter("isbn has not a valid format")
}
}
private def validateTitle(title: String): Try[String] = Try {
if (Option(title).forall(_.isEmpty)) throw new InvalidParameter("title must not be empty") else title
}
private def validateAuthor(author: String): Try[String] = Try {
if (Option(author).forall(_.isEmpty)) throw new InvalidParameter("author must not be empty") else author
}
Encapsulando excepciones con Try
import cats.syntax.semigroup._
//Valida los libros y devuelve una lista no vacía en el caso Success
def validateBook(b: Book): Try[NonEmptyList[Book]] =
for {
i <- validateIsbn(b.isbn)
a <- validateAuthor(b.author)
t <- validateTitle(b.title)
g <- validateGenre(b.genre)
} yield NonEmptyList.of(Book(i, t, a, g))
//Combina los resultados exitosos del Try en una lista no vacía
def validateBooks(bs: List[Book]): Try[NonEmptyList[Book]] = bs match {
case Nil => Failure(new EmptyBookList("Book list was empty"))
case books => books map validateBook reduce (_ |+| _)
}
Encapsulando excepciones con Try
"BookValidation" should {
"Validate a book" in {
val validated = validateBook(theFountainhead)
validated should === (Success(NonEmptyList(theFountainhead, Nil)))
}
"Validate books" in {
val validatedBooks = validateBooks(List(theFountainhead, atlasShrugged))
validatedBooks should === (Success(NonEmptyList(theFountainhead, atlasShrugged :: Nil)))
}
"Fail fast error on books" in {
val validatedBooks = validateBooks(List(titlelessBook, theCountOfMontecristo, theFountainhead))
inside(validatedBooks) { case Failure(ex) => ex.getMessage shouldBe "title must not be empty" }
}
}
Errores como parte del dominio
● Un error en una función no debe tratarse como algo excepcional.
● Excepciones para interacciones con la capa de infraestructura.
● Excepciones rompen con type safety.
● Los errores también son parte del dominio.
//No es cierto que validateBook siempre devuelve un Book
def validateBook(book: Book): Book = {
validateGenre(book.genre)
validateIsbn(book.isbn)
validateTitle(book.title)
validateAuthor(book.author)
book
}
Errores como parte del dominio
sealed trait Error extends Product with Serializable {
val message: String
}
case class InvalidParameter(message: String) extends Error
case class EmptyBookList(message: String) extends Error
Definimos las excepciones anteriormente usadas como ADTs de Error.
Manejo de errores con Scala Either
● El tipo Either[A, B] representa el valor de dos tipos posibles: Left o Right
● Convencionalmente se usa el Left para representar errores y Right para
representar los aciertos.
● Nos facilita manejar los errores modelados como parte del dominio.
● Se puede usar for comprehension.
● Es fail fast en Left.
Manejo de errores con Scala Either
private def validateGenre(g: Genre): Either[InvalidParameter, Genre] = g match {
case InvalidGenre => Left(InvalidParameter("Book has invalid genre"))
case genre => Right(genre)
}
private def validateIsbn(isbn: String): Either[InvalidParameter, String] = isbn match {
case isbnRegex(all @ _*) => Right(isbn)
case _ => Left(InvalidParameter("isbn has not a valid format"))
}
private def validateTitle(title: String): Either[InvalidParameter, String] =
if (Option(title).forall(_.isEmpty)) Left(InvalidParameter("title must not be empty")) else Right(title)
private def validateAuthor(author: String): Either[InvalidParameter, String] =
if (Option(author).forall(_.isEmpty)) Left(InvalidParameter("author must not be empty")) else Right(author)
Manejo de errores con Scala Either
import cats.syntax.semigroup._
//Valida secuencialmente todos los campos, se detiene en el primer error encontrado.
def validateBook(b: Book): Either[InvalidParameter, NonEmptyList[Book]] =
for {
i <- validateIsbn(b.isbn)
a <- validateAuthor(b.author)
t <- validateTitle(b.title)
g <- validateGenre(b.genre)
} yield NonEmptyList.of(Book(i, t, a, g))
//Por ser fail fast, reporta el primer error encontrado pero acumula todos los aciertos.
def validateBooks(bs: List[Book]): Either[Error, NonEmptyList[Book]] = bs match {
case Nil => Left(EmptyBookList("Book list was empty"))
case books => books map validateBook reduce (_ |+| _)
}
Manejo de errores con Scala Either
"BookValidation" should {
"Validate a book" in {
val validated = validateBook(theFountainhead)
validated should === (Right(NonEmptyList(theFountainhead, Nil)))
}
"Validate books" in {
val validatedBooks = validateBooks(List(theFountainhead, atlasShrugged))
validatedBooks should === (Right(NonEmptyList(theFountainhead, atlasShrugged :: Nil)))
}
"Fail fast error on books" in {
val validatedBooks = validateBooks(List(titlelessBook, theCountOfMontecristo, theFountainhead))
validatedBooks should === (Left(InvalidParameter("title must not be empty")))
}
}
Manejo de errores con Cats Validated
● El tipo Validated[A, B] representa el valor de dos tipos posibles: Valid e
Invalid.
● Desde el punto de vista semántico, es obvio que Invalid es utilizado para
representar los errores y Valid los aciertos.
● Nos facilita manejar los errores modelados como parte del dominio.
● No se puede utilizar en for comprehension.
● Acumula errores en Invalid ( type ValidatedNel[A, B] =
Validated[NonEmptyList[A], B] ).
Manejo de errores con Cats Validated
private def validateGenre(g: Genre): ValidatedNel[InvalidParameter, Genre] = g match {
case InvalidGenre => InvalidParameter("Book has invalid genre").invalidNel
case genre => genre.validNel
}
private def validateIsbn(isbn: String): ValidatedNel[InvalidParameter, String] = isbn match {
case isbnRegex(all @ _*) => isbn.validNel
case _ => InvalidParameter("isbn has not a valid format").invalidNel
}
private def validateTitle(title: String): ValidatedNel[InvalidParameter, String] =
if (Option(title).exists(_.isEmpty)) InvalidParameter("title must not be empty").invalidNel else title.validNel
private def validateAuthor(author: String): ValidatedNel[InvalidParameter, String] =
if (Option(author).exists(_.isEmpty)) InvalidParameter("author must not be empty").invalidNel
else author.validNel
Manejo de errores con Cats Validated
import cats.syntax.cartesian._
import cats.syntax.semigroup._
//Valida en el producto cartesiano, acumula los errores en cada validación.
def validateBook(b: Book): ValidatedNel[InvalidParameter, NonEmptyList[Book]] = (
validateIsbn(b.isbn) |@|
validateAuthor(b.author) |@|
validateTitle(b.title) |@|
validateGenre(b.genre) ) map {
case (isbn, author, title, genre) =>
NonEmptyList.of(Book(isbn, title, author, genre))
}
//Puede acumular todos los errores o acumular todos los aciertos.
def validateBooks(bs: List[Book]): ValidatedNel[Error, NonEmptyList[Book]] = bs match {
case Nil => EmptyBookList("Book list was empty").invalidNel
case books => books map validateBook reduce (_ |+| _)
}
Manejo de errores con Cats Validated
"BookValidation" should {
"Validate books" in {
val validatedBooks = validateBooks(List(theFountainhead, atlasShrugged))
validatedBooks should === (Valid(NonEmptyList(theFountainhead, atlasShrugged :: Nil)))
}
"Accumulate errors on books" in {
val validatedBooks = validateBooks(List(titlelessBook, theCountOfMontecristo, theFountainhead))
validatedBooks should === (
Invalid(
NonEmptyList(InvalidParameter("title must not be empty"),
InvalidParameter("Book has invalid genre") :: InvalidParameter("isbn has not a valid format") :: Nil)
)
)
}
}
Manejo de errores con Cats Ior
● El tipo Ior[A, B] representa el valor de tres tipos posibles: Ior.Right,
Ior.Left e Ior.Both.
● La convención con Ior.Left e Ior.Right es igual a la de Either con respecto
a la representación de errores y aciertos.
● Ior.Both permite incluir simultáneamente los errores y aciertos
● Nos facilita manejar los errores modelados como parte del dominio.
● Se puede utilizar en for comprehension.
● Es fail fast en Ior.Left y acumula errores en Ior.Both.
Manejo de errores con Cats Ior
private def validateGenre(g: Genre): IorNel[InvalidParameter, Genre] = g match {
case InvalidGenre => Ior.left(NonEmptyList.of(InvalidParameter("Book has invalid genre")))
case genre => Ior.right(genre)
}
private def validateIsbn(isbn: String): IorNel[InvalidParameter, String] = isbn match {
case isbnRegex(all @ _*) => Ior.right(isbn)
case _ => Ior.left(NonEmptyList.of(InvalidParameter("isbn has not a valid format")))
}
private def validateTitle(title: String): IorNel[InvalidParameter, String] =
if (Option(title).exists(_.isEmpty)) Ior.left(NonEmptyList.of(InvalidParameter("title must not be empty")))
else Ior.right(title)
private def validateAuthor(author: String): IorNel[InvalidParameter, String] =
if (Option(author).exists(_.isEmpty)) Ior.left(NonEmptyList.of(InvalidParameter("author must not be empty")))
else Ior.right(author)
Manejo de errores con Cats Ior
import cats.syntax.semigroup._
//Valida los campos secuencialmente, se detiene en el primer error.
def validateBook(b: Book): IorNel[InvalidParameter, NonEmptyList[Book]] =
for {
i <- validateIsbn(b.isbn)
a <- validateAuthor(b.author)
t <- validateTitle(b.title)
g <- validateGenre(b.genre)
} yield NonEmptyList.of(Book(i, t, a, g))
//A diferencia de Validated, puede acumular errores y aciertos en Ior.Both
def validateBooks(bs: List[Book]): IorNel[Error, NonEmptyList[Book]] = bs match {
case Nil => Ior.left(EmptyBookList("Book list was empty"))
case books => books map validateBook reduce (_ |+| _)
}
Manejo de errores con Cats Ior
"BookValidation" should {
"Validate books" in {
val validatedBooks = validateBooks(List(theFountainhead, atlasShrugged))
validatedBooks should === (Ior.Right(NonEmptyList(theFountainhead, atlasShrugged :: Nil)))
}
"Fail fast error on books" in {
val validatedBooks = validateBooks(List(titlelessBook, theCountOfMontecristo, theFountainhead, atlasShrugged))
validatedBooks should === (
Ior.Both(
NonEmptyList(InvalidParameter("title must not be empty"),InvalidParameter("isbn has not a valid format") :: Nil),
NonEmptyList(theFountainhead, atlasShrugged :: Nil)
)
)
}
}
Conclusiones
● En una función no se deben arrojar excepciones, se pierde transparencia
referencial.
● Se favorece la modelación de errores en el dominio.
● Try es fail fast, no es expresivo en cuanto a los errores que encapsula y
se puede usar cuando se depende de métodos de librerías java.
● Either es fail fast y puede acumular aciertos.
● Validated acumula errores, no se puede usar en for comprehensions y
puede acumular aciertos.
● Ior es el más flexible: es fail fast en Ior.Left, acumula errores en Ior.Both y
puede acumular aciertos en Ior.Right e Ior.Both.
¿Preguntas?

Más contenido relacionado

Destacado

незмінювані іменники
незмінювані іменникинезмінювані іменники
незмінювані іменникиmilona14
 
Total Rewards Spectrum Health
Total Rewards Spectrum Health Total Rewards Spectrum Health
Total Rewards Spectrum Health Laura Steffer
 
Santa Fe Avenue Streetscape-Survey #2 Results
Santa Fe Avenue Streetscape-Survey #2 ResultsSanta Fe Avenue Streetscape-Survey #2 Results
Santa Fe Avenue Streetscape-Survey #2 ResultsCity of Salina
 
Rassegna stampa 28 marzo del Teatro Franco Parenti
Rassegna stampa 28 marzo del Teatro Franco Parenti Rassegna stampa 28 marzo del Teatro Franco Parenti
Rassegna stampa 28 marzo del Teatro Franco Parenti Francesco Malcangio
 
Trip to the museum of London
Trip to the museum of LondonTrip to the museum of London
Trip to the museum of Londonleonaoti
 
Reach.UrFaculty - Govt. Jobs Update Mar 27
Reach.UrFaculty - Govt. Jobs Update Mar 27Reach.UrFaculty - Govt. Jobs Update Mar 27
Reach.UrFaculty - Govt. Jobs Update Mar 27Reshmaurfaculty
 
Presentation on Online Learning at UET Peshawar
Presentation on Online Learning at UET PeshawarPresentation on Online Learning at UET Peshawar
Presentation on Online Learning at UET PeshawarAtif Ur Rahman
 
Information of the senses
Information of the sensesInformation of the senses
Information of the sensesŠkola Futura
 
Investing in Portugal - Portuguese Company [Episode 04]
Investing in Portugal - Portuguese Company [Episode 04]Investing in Portugal - Portuguese Company [Episode 04]
Investing in Portugal - Portuguese Company [Episode 04]UWU Solutions, Lda.
 
Executive Summary of 2017 African Commercial Vehicle Industry
Executive Summary of 2017 African Commercial Vehicle IndustryExecutive Summary of 2017 African Commercial Vehicle Industry
Executive Summary of 2017 African Commercial Vehicle IndustryLakshmi Narayanan Ramanujam
 

Destacado (14)

незмінювані іменники
незмінювані іменникинезмінювані іменники
незмінювані іменники
 
Total Rewards Spectrum Health
Total Rewards Spectrum Health Total Rewards Spectrum Health
Total Rewards Spectrum Health
 
парад талантов
парад талантовпарад талантов
парад талантов
 
Santa Fe Avenue Streetscape-Survey #2 Results
Santa Fe Avenue Streetscape-Survey #2 ResultsSanta Fe Avenue Streetscape-Survey #2 Results
Santa Fe Avenue Streetscape-Survey #2 Results
 
Rassegna stampa 28 marzo del Teatro Franco Parenti
Rassegna stampa 28 marzo del Teatro Franco Parenti Rassegna stampa 28 marzo del Teatro Franco Parenti
Rassegna stampa 28 marzo del Teatro Franco Parenti
 
Trip to the museum of London
Trip to the museum of LondonTrip to the museum of London
Trip to the museum of London
 
Reach.UrFaculty - Govt. Jobs Update Mar 27
Reach.UrFaculty - Govt. Jobs Update Mar 27Reach.UrFaculty - Govt. Jobs Update Mar 27
Reach.UrFaculty - Govt. Jobs Update Mar 27
 
7. evaluation(2)
7. evaluation(2)7. evaluation(2)
7. evaluation(2)
 
Presentation on Online Learning at UET Peshawar
Presentation on Online Learning at UET PeshawarPresentation on Online Learning at UET Peshawar
Presentation on Online Learning at UET Peshawar
 
Information of the senses
Information of the sensesInformation of the senses
Information of the senses
 
Investing in Portugal - Portuguese Company [Episode 04]
Investing in Portugal - Portuguese Company [Episode 04]Investing in Portugal - Portuguese Company [Episode 04]
Investing in Portugal - Portuguese Company [Episode 04]
 
Case study WhatsNext
Case study WhatsNextCase study WhatsNext
Case study WhatsNext
 
Analytics in Online Retail
Analytics in Online RetailAnalytics in Online Retail
Analytics in Online Retail
 
Executive Summary of 2017 African Commercial Vehicle Industry
Executive Summary of 2017 African Commercial Vehicle IndustryExecutive Summary of 2017 African Commercial Vehicle Industry
Executive Summary of 2017 African Commercial Vehicle Industry
 

Similar a Manejo de errores con typelevel.cats

Elementos del Hardware y Software
Elementos del Hardware y SoftwareElementos del Hardware y Software
Elementos del Hardware y Softwarecarlosadrianev
 
RegExp JavaScript Expresiones Regulares
RegExp JavaScript Expresiones RegularesRegExp JavaScript Expresiones Regulares
RegExp JavaScript Expresiones RegularesIsabel Gómez
 
Metaprogramación (en Ruby): programas que escriben programas
Metaprogramación (en Ruby): programas que escriben programasMetaprogramación (en Ruby): programas que escriben programas
Metaprogramación (en Ruby): programas que escriben programasSergio Gil
 

Similar a Manejo de errores con typelevel.cats (8)

Tema2[php]
Tema2[php]Tema2[php]
Tema2[php]
 
Elementos del Hardware y Software
Elementos del Hardware y SoftwareElementos del Hardware y Software
Elementos del Hardware y Software
 
Ruby 01
Ruby 01Ruby 01
Ruby 01
 
Ruby
Ruby Ruby
Ruby
 
Php
PhpPhp
Php
 
RegExp JavaScript Expresiones Regulares
RegExp JavaScript Expresiones RegularesRegExp JavaScript Expresiones Regulares
RegExp JavaScript Expresiones Regulares
 
Javascript C#
Javascript C#Javascript C#
Javascript C#
 
Metaprogramación (en Ruby): programas que escriben programas
Metaprogramación (en Ruby): programas que escriben programasMetaprogramación (en Ruby): programas que escriben programas
Metaprogramación (en Ruby): programas que escriben programas
 

Último

trabajotecologiaisabella-240424003133-8f126965.pdf
trabajotecologiaisabella-240424003133-8f126965.pdftrabajotecologiaisabella-240424003133-8f126965.pdf
trabajotecologiaisabella-240424003133-8f126965.pdfIsabellaMontaomurill
 
EPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveEPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveFagnerLisboa3
 
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricGlobal Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricKeyla Dolores Méndez
 
KELA Presentacion Costa Rica 2024 - evento Protégeles
KELA Presentacion Costa Rica 2024 - evento ProtégelesKELA Presentacion Costa Rica 2024 - evento Protégeles
KELA Presentacion Costa Rica 2024 - evento ProtégelesFundación YOD YOD
 
Cortes-24-de-abril-Tungurahua-3 año 2024
Cortes-24-de-abril-Tungurahua-3 año 2024Cortes-24-de-abril-Tungurahua-3 año 2024
Cortes-24-de-abril-Tungurahua-3 año 2024GiovanniJavierHidalg
 
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE  DE TECNOLOGIA E INFORMATICA PRIMARIACLASE  DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIAWilbisVega
 
Proyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptxProyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptx241521559
 
Plan de aula informatica segundo periodo.docx
Plan de aula informatica segundo periodo.docxPlan de aula informatica segundo periodo.docx
Plan de aula informatica segundo periodo.docxpabonheidy28
 
La era de la educación digital y sus desafios
La era de la educación digital y sus desafiosLa era de la educación digital y sus desafios
La era de la educación digital y sus desafiosFundación YOD YOD
 
International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)GDGSucre
 
Trabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíaTrabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíassuserf18419
 
Redes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfRedes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfsoporteupcology
 
guía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Josephguía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan JosephBRAYANJOSEPHPEREZGOM
 
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...silviayucra2
 
9egb-lengua y Literatura.pdf_texto del estudiante
9egb-lengua y Literatura.pdf_texto del estudiante9egb-lengua y Literatura.pdf_texto del estudiante
9egb-lengua y Literatura.pdf_texto del estudianteAndreaHuertas24
 
Hernandez_Hernandez_Practica web de la sesion 12.pptx
Hernandez_Hernandez_Practica web de la sesion 12.pptxHernandez_Hernandez_Practica web de la sesion 12.pptx
Hernandez_Hernandez_Practica web de la sesion 12.pptxJOSEMANUELHERNANDEZH11
 

Último (16)

trabajotecologiaisabella-240424003133-8f126965.pdf
trabajotecologiaisabella-240424003133-8f126965.pdftrabajotecologiaisabella-240424003133-8f126965.pdf
trabajotecologiaisabella-240424003133-8f126965.pdf
 
EPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveEPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial Uninove
 
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricGlobal Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
 
KELA Presentacion Costa Rica 2024 - evento Protégeles
KELA Presentacion Costa Rica 2024 - evento ProtégelesKELA Presentacion Costa Rica 2024 - evento Protégeles
KELA Presentacion Costa Rica 2024 - evento Protégeles
 
Cortes-24-de-abril-Tungurahua-3 año 2024
Cortes-24-de-abril-Tungurahua-3 año 2024Cortes-24-de-abril-Tungurahua-3 año 2024
Cortes-24-de-abril-Tungurahua-3 año 2024
 
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE  DE TECNOLOGIA E INFORMATICA PRIMARIACLASE  DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
 
Proyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptxProyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptx
 
Plan de aula informatica segundo periodo.docx
Plan de aula informatica segundo periodo.docxPlan de aula informatica segundo periodo.docx
Plan de aula informatica segundo periodo.docx
 
La era de la educación digital y sus desafios
La era de la educación digital y sus desafiosLa era de la educación digital y sus desafios
La era de la educación digital y sus desafios
 
International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)
 
Trabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíaTrabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnología
 
Redes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfRedes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdf
 
guía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Josephguía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Joseph
 
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
 
9egb-lengua y Literatura.pdf_texto del estudiante
9egb-lengua y Literatura.pdf_texto del estudiante9egb-lengua y Literatura.pdf_texto del estudiante
9egb-lengua y Literatura.pdf_texto del estudiante
 
Hernandez_Hernandez_Practica web de la sesion 12.pptx
Hernandez_Hernandez_Practica web de la sesion 12.pptxHernandez_Hernandez_Practica web de la sesion 12.pptx
Hernandez_Hernandez_Practica web de la sesion 12.pptx
 

Manejo de errores con typelevel.cats

  • 1. Manejo de errores con typelevel.cats
  • 2. El recorrido ● Error y Excepción. ● El excepcionalismo imperativo. ● Encapsular excepciones en Try. ● Errores como parte del dominio. ● Manejo de errores con Scala Either. ● Acumular errores con Validated. ● Reportar errores y aciertos con Ior. ● Conclusiones.
  • 3. Error y Excepción ● Error: resultado no deseado de la evaluación de un programa. ● Excepción: condición excepcional del programa en tiempo de ejecución.
  • 4. El excepcionalismo imperativo ● Durante la evaluación de un método, si se encuentra un error se arroja una excepción. ● Este paradigma puede tener su origen en: ○ Lenguajes imperativos sin un sistema de tipos robusto. ○ Considerando lo anterior, carencia de tipos de datos (datatypes) que permitan manejar los errores. ● Se requiere try/catch para manejar los métodos que puedan arrojar excepciones.
  • 5. El dominio case class Book(isbn: String, title: String, author: String, genre: Genre) trait Genre extends Product with Serializable object Genre { case object Fiction extends Genre case object ScienceFiction extends Genre case object HistoricNovel extends Genre case object InvalidGenre extends Genre } val theFountainhead = Book("ISBN: 978-1-4028-9462-6","The Fountainhead","Ayn Rand",Genre.Fiction) val atlasShrugged = Book("ISBN-13 978-1-4028-9462-6","Atlas Shrugged","Ayn Rand",Genre.Fiction) val theCountOfMontecristo = Book("ISBN-13 978-1-4028-9462","The Count Of Montecristo","Alexandre Dumas",Genre.HistoricNovel) val titlelessBook = Book("ISBN-13 978-1-4028-9462-6","","Unknown",Genre.InvalidGenre) Un libro con isbn, título, autor y género.
  • 6. El excepcionalismo imperativo private def validateGenre(g: Genre): Unit = if ( g == Genre.InvalidGenre ) throw new InvalidParameter("Book has invalid genre") private def validateIsbn(isbn: String): Unit = isbn match { case isbnRegex(all @ _*) => () case _ => throw new InvalidParameter("isbn has not a valid format") } private def validateTitle(title: String): Unit = if (title.isEmpty || title == null) throw new InvalidParameter("title must not be empty") private def validateAuthor(author: String): Unit = if (author.isEmpty || author == null) throw new InvalidParameter("author must not be empty") class InvalidParameter(message: String) extends Exception(message) class EmptyBookList(message: String) extends Exception(message)
  • 7. El excepcionalismo imperativo def validateBook(book: Book): Book = { validateGenre(book.genre) validateIsbn(book.isbn) validateTitle(book.title) validateAuthor(book.author) book } def validateBooks(books: List[Book]): List[Book] = if (books == Nil) throw new EmptyBookList("Book list was empty") else { val booksBuffer = new ListBuffer[Book] for (book <- books) { try booksBuffer += validateBook(book) catch { case ex: Exception => println(s"Error $ex") } } booksBuffer.toList }
  • 8. Encapsulando excepciones con Try ● El tipo Try[A] es utilizado para manejar excepciones en métodos. ● Encapsula el resultado en dos subtipos: Success y Failure. ● Success contiene el resultado del método. ● Failure contiene la excepción arrojada. ● Nos permite usar for comprehension. ● Es fail fast en Failure.
  • 9. Encapsulando excepciones con Try private def validateGenre(g: Genre): Try[Genre] = Try { g match { case Genre.InvalidGenre => throw new InvalidParameter("Book has invalid genre") case genre => genre } } private def validateIsbn(isbn: String): Try[String] = Try { isbn match { case isbnRegex(all @ _*) => isbn case _ => throw new InvalidParameter("isbn has not a valid format") } } private def validateTitle(title: String): Try[String] = Try { if (Option(title).forall(_.isEmpty)) throw new InvalidParameter("title must not be empty") else title } private def validateAuthor(author: String): Try[String] = Try { if (Option(author).forall(_.isEmpty)) throw new InvalidParameter("author must not be empty") else author }
  • 10. Encapsulando excepciones con Try import cats.syntax.semigroup._ //Valida los libros y devuelve una lista no vacía en el caso Success def validateBook(b: Book): Try[NonEmptyList[Book]] = for { i <- validateIsbn(b.isbn) a <- validateAuthor(b.author) t <- validateTitle(b.title) g <- validateGenre(b.genre) } yield NonEmptyList.of(Book(i, t, a, g)) //Combina los resultados exitosos del Try en una lista no vacía def validateBooks(bs: List[Book]): Try[NonEmptyList[Book]] = bs match { case Nil => Failure(new EmptyBookList("Book list was empty")) case books => books map validateBook reduce (_ |+| _) }
  • 11. Encapsulando excepciones con Try "BookValidation" should { "Validate a book" in { val validated = validateBook(theFountainhead) validated should === (Success(NonEmptyList(theFountainhead, Nil))) } "Validate books" in { val validatedBooks = validateBooks(List(theFountainhead, atlasShrugged)) validatedBooks should === (Success(NonEmptyList(theFountainhead, atlasShrugged :: Nil))) } "Fail fast error on books" in { val validatedBooks = validateBooks(List(titlelessBook, theCountOfMontecristo, theFountainhead)) inside(validatedBooks) { case Failure(ex) => ex.getMessage shouldBe "title must not be empty" } } }
  • 12. Errores como parte del dominio ● Un error en una función no debe tratarse como algo excepcional. ● Excepciones para interacciones con la capa de infraestructura. ● Excepciones rompen con type safety. ● Los errores también son parte del dominio. //No es cierto que validateBook siempre devuelve un Book def validateBook(book: Book): Book = { validateGenre(book.genre) validateIsbn(book.isbn) validateTitle(book.title) validateAuthor(book.author) book }
  • 13. Errores como parte del dominio sealed trait Error extends Product with Serializable { val message: String } case class InvalidParameter(message: String) extends Error case class EmptyBookList(message: String) extends Error Definimos las excepciones anteriormente usadas como ADTs de Error.
  • 14. Manejo de errores con Scala Either ● El tipo Either[A, B] representa el valor de dos tipos posibles: Left o Right ● Convencionalmente se usa el Left para representar errores y Right para representar los aciertos. ● Nos facilita manejar los errores modelados como parte del dominio. ● Se puede usar for comprehension. ● Es fail fast en Left.
  • 15. Manejo de errores con Scala Either private def validateGenre(g: Genre): Either[InvalidParameter, Genre] = g match { case InvalidGenre => Left(InvalidParameter("Book has invalid genre")) case genre => Right(genre) } private def validateIsbn(isbn: String): Either[InvalidParameter, String] = isbn match { case isbnRegex(all @ _*) => Right(isbn) case _ => Left(InvalidParameter("isbn has not a valid format")) } private def validateTitle(title: String): Either[InvalidParameter, String] = if (Option(title).forall(_.isEmpty)) Left(InvalidParameter("title must not be empty")) else Right(title) private def validateAuthor(author: String): Either[InvalidParameter, String] = if (Option(author).forall(_.isEmpty)) Left(InvalidParameter("author must not be empty")) else Right(author)
  • 16. Manejo de errores con Scala Either import cats.syntax.semigroup._ //Valida secuencialmente todos los campos, se detiene en el primer error encontrado. def validateBook(b: Book): Either[InvalidParameter, NonEmptyList[Book]] = for { i <- validateIsbn(b.isbn) a <- validateAuthor(b.author) t <- validateTitle(b.title) g <- validateGenre(b.genre) } yield NonEmptyList.of(Book(i, t, a, g)) //Por ser fail fast, reporta el primer error encontrado pero acumula todos los aciertos. def validateBooks(bs: List[Book]): Either[Error, NonEmptyList[Book]] = bs match { case Nil => Left(EmptyBookList("Book list was empty")) case books => books map validateBook reduce (_ |+| _) }
  • 17. Manejo de errores con Scala Either "BookValidation" should { "Validate a book" in { val validated = validateBook(theFountainhead) validated should === (Right(NonEmptyList(theFountainhead, Nil))) } "Validate books" in { val validatedBooks = validateBooks(List(theFountainhead, atlasShrugged)) validatedBooks should === (Right(NonEmptyList(theFountainhead, atlasShrugged :: Nil))) } "Fail fast error on books" in { val validatedBooks = validateBooks(List(titlelessBook, theCountOfMontecristo, theFountainhead)) validatedBooks should === (Left(InvalidParameter("title must not be empty"))) } }
  • 18. Manejo de errores con Cats Validated ● El tipo Validated[A, B] representa el valor de dos tipos posibles: Valid e Invalid. ● Desde el punto de vista semántico, es obvio que Invalid es utilizado para representar los errores y Valid los aciertos. ● Nos facilita manejar los errores modelados como parte del dominio. ● No se puede utilizar en for comprehension. ● Acumula errores en Invalid ( type ValidatedNel[A, B] = Validated[NonEmptyList[A], B] ).
  • 19. Manejo de errores con Cats Validated private def validateGenre(g: Genre): ValidatedNel[InvalidParameter, Genre] = g match { case InvalidGenre => InvalidParameter("Book has invalid genre").invalidNel case genre => genre.validNel } private def validateIsbn(isbn: String): ValidatedNel[InvalidParameter, String] = isbn match { case isbnRegex(all @ _*) => isbn.validNel case _ => InvalidParameter("isbn has not a valid format").invalidNel } private def validateTitle(title: String): ValidatedNel[InvalidParameter, String] = if (Option(title).exists(_.isEmpty)) InvalidParameter("title must not be empty").invalidNel else title.validNel private def validateAuthor(author: String): ValidatedNel[InvalidParameter, String] = if (Option(author).exists(_.isEmpty)) InvalidParameter("author must not be empty").invalidNel else author.validNel
  • 20. Manejo de errores con Cats Validated import cats.syntax.cartesian._ import cats.syntax.semigroup._ //Valida en el producto cartesiano, acumula los errores en cada validación. def validateBook(b: Book): ValidatedNel[InvalidParameter, NonEmptyList[Book]] = ( validateIsbn(b.isbn) |@| validateAuthor(b.author) |@| validateTitle(b.title) |@| validateGenre(b.genre) ) map { case (isbn, author, title, genre) => NonEmptyList.of(Book(isbn, title, author, genre)) } //Puede acumular todos los errores o acumular todos los aciertos. def validateBooks(bs: List[Book]): ValidatedNel[Error, NonEmptyList[Book]] = bs match { case Nil => EmptyBookList("Book list was empty").invalidNel case books => books map validateBook reduce (_ |+| _) }
  • 21. Manejo de errores con Cats Validated "BookValidation" should { "Validate books" in { val validatedBooks = validateBooks(List(theFountainhead, atlasShrugged)) validatedBooks should === (Valid(NonEmptyList(theFountainhead, atlasShrugged :: Nil))) } "Accumulate errors on books" in { val validatedBooks = validateBooks(List(titlelessBook, theCountOfMontecristo, theFountainhead)) validatedBooks should === ( Invalid( NonEmptyList(InvalidParameter("title must not be empty"), InvalidParameter("Book has invalid genre") :: InvalidParameter("isbn has not a valid format") :: Nil) ) ) } }
  • 22. Manejo de errores con Cats Ior ● El tipo Ior[A, B] representa el valor de tres tipos posibles: Ior.Right, Ior.Left e Ior.Both. ● La convención con Ior.Left e Ior.Right es igual a la de Either con respecto a la representación de errores y aciertos. ● Ior.Both permite incluir simultáneamente los errores y aciertos ● Nos facilita manejar los errores modelados como parte del dominio. ● Se puede utilizar en for comprehension. ● Es fail fast en Ior.Left y acumula errores en Ior.Both.
  • 23. Manejo de errores con Cats Ior private def validateGenre(g: Genre): IorNel[InvalidParameter, Genre] = g match { case InvalidGenre => Ior.left(NonEmptyList.of(InvalidParameter("Book has invalid genre"))) case genre => Ior.right(genre) } private def validateIsbn(isbn: String): IorNel[InvalidParameter, String] = isbn match { case isbnRegex(all @ _*) => Ior.right(isbn) case _ => Ior.left(NonEmptyList.of(InvalidParameter("isbn has not a valid format"))) } private def validateTitle(title: String): IorNel[InvalidParameter, String] = if (Option(title).exists(_.isEmpty)) Ior.left(NonEmptyList.of(InvalidParameter("title must not be empty"))) else Ior.right(title) private def validateAuthor(author: String): IorNel[InvalidParameter, String] = if (Option(author).exists(_.isEmpty)) Ior.left(NonEmptyList.of(InvalidParameter("author must not be empty"))) else Ior.right(author)
  • 24. Manejo de errores con Cats Ior import cats.syntax.semigroup._ //Valida los campos secuencialmente, se detiene en el primer error. def validateBook(b: Book): IorNel[InvalidParameter, NonEmptyList[Book]] = for { i <- validateIsbn(b.isbn) a <- validateAuthor(b.author) t <- validateTitle(b.title) g <- validateGenre(b.genre) } yield NonEmptyList.of(Book(i, t, a, g)) //A diferencia de Validated, puede acumular errores y aciertos en Ior.Both def validateBooks(bs: List[Book]): IorNel[Error, NonEmptyList[Book]] = bs match { case Nil => Ior.left(EmptyBookList("Book list was empty")) case books => books map validateBook reduce (_ |+| _) }
  • 25. Manejo de errores con Cats Ior "BookValidation" should { "Validate books" in { val validatedBooks = validateBooks(List(theFountainhead, atlasShrugged)) validatedBooks should === (Ior.Right(NonEmptyList(theFountainhead, atlasShrugged :: Nil))) } "Fail fast error on books" in { val validatedBooks = validateBooks(List(titlelessBook, theCountOfMontecristo, theFountainhead, atlasShrugged)) validatedBooks should === ( Ior.Both( NonEmptyList(InvalidParameter("title must not be empty"),InvalidParameter("isbn has not a valid format") :: Nil), NonEmptyList(theFountainhead, atlasShrugged :: Nil) ) ) } }
  • 26. Conclusiones ● En una función no se deben arrojar excepciones, se pierde transparencia referencial. ● Se favorece la modelación de errores en el dominio. ● Try es fail fast, no es expresivo en cuanto a los errores que encapsula y se puede usar cuando se depende de métodos de librerías java. ● Either es fail fast y puede acumular aciertos. ● Validated acumula errores, no se puede usar en for comprehensions y puede acumular aciertos. ● Ior es el más flexible: es fail fast en Ior.Left, acumula errores en Ior.Both y puede acumular aciertos en Ior.Right e Ior.Both.