15. ¿Por qué ZIO?
ZIO nos da súperpoderes y nos
ayuda a ser más productivos a la
hora de construir aplicaciones
modernas:
9/60
16. ¿Por qué ZIO?
ZIO nos da súperpoderes y nos
ayuda a ser más productivos a la
hora de construir aplicaciones
modernas:
— Resolver problemas con
menos esfuerzo
9/60
17. ¿Por qué ZIO?
ZIO nos da súperpoderes y nos
ayuda a ser más productivos a la
hora de construir aplicaciones
modernas:
— Resolver problemas con
menos esfuerzo
— Menor costo de
mantenimiento
9/60
18. ¿Por qué ZIO?
ZIO nos da súperpoderes y nos
ayuda a ser más productivos a la
hora de construir aplicaciones
modernas:
— Resolver problemas con
menos esfuerzo
— Menor costo de
mantenimiento
— Proporciona mayores garantías
en tiempo de compilación
9/60
35. ZIO... Porque es ideal para Programación Asíncrona
// ¡Adiós callbacks!
// ZIO es 100% asíncrono, pero con bloqueo semántico
val enrich =
(for {
value <- s3Get(key)
_ <- s3Put(key, enrichProfile(value))
} yield ()).catchAll(error => log(error))
18/60
36. ZIO... Porque es ideal para Programación Asíncrona
// ¡Adiós callbacks!
// ZIO es 100% asíncrono, pero con bloqueo semántico
val enrich =
(for {
value <- s3Get(key)
_ <- s3Put(key, enrichProfile(value))
} yield ()).catchAll(error => log(error))
18/60
37. ZIO... Porque es ideal para Programación Asíncrona
// ¡Adiós callbacks!
// ZIO es 100% asíncrono, pero con bloqueo semántico
val enrich =
(for {
value <- s3Get(key)
_ <- s3Put(key, enrichProfile(value))
} yield ()).catchAll(error => log(error))
18/60
38. ZIO... Porque es ideal para Programación Asíncrona
// ¡Adiós callbacks!
// ZIO es 100% asíncrono, pero con bloqueo semántico
val enrich =
(for {
value <- s3Get(key)
_ <- s3Put(key, enrichProfile(value))
} yield ()).catchAll(error => log(error))
18/60
39. ZIO... Porque es ideal para Programación Asíncrona
// ¡Adiós callbacks!
// ZIO es 100% asíncrono, pero con bloqueo semántico
val enrich =
(for {
value <- s3Get(key)
_ <- s3Put(key, enrichProfile(value))
} yield ()).catchAll(error => log(error))
18/60
40. ZIO... Porque es ideal para Programación Asíncrona
// ¡Adiós callbacks!
// ZIO es 100% asíncrono, pero con bloqueo semántico
val enrich =
(for {
value <- s3Get(key)
_ <- s3Put(key, enrichProfile(value))
} yield ()).catchAll(error => log(error))
18/60
41. ZIO... Porque permite maximizar el Parelelismo en una
aplicación
// Procesa cada URL de forma secuencial
ZIO.foreach(urls) { url =>
for {
data <- load(url)
json <- parseToJson(data)
transformed <- transform(json)
} yield transformed
}
19/60
42. ZIO... Porque permite maximizar el Parelelismo en una
aplicación
// Procesa cada URL de forma secuencial
ZIO.foreach(urls) { url =>
for {
data <- load(url)
json <- parseToJson(data)
transformed <- transform(json)
} yield transformed
}
19/60
43. ZIO... Porque permite maximizar el Parelelismo en una
aplicación
// Procesa cada URL de forma secuencial
ZIO.foreach(urls) { url =>
for {
data <- load(url)
json <- parseToJson(data)
transformed <- transform(json)
} yield transformed
}
19/60
44. ZIO... Porque permite maximizar el Parelelismo en una
aplicación
// ¡Paralelizar con control preciso es trivial!
ZIO.foreachParN(20)(urls) { url =>
for {
data <- load(url)
json <- parseToJson(data)
transformed <- transform(json)
} yield transformed
}
20/60
45. ZIO... Porque permite maximizar el Parelelismo en una
aplicación
// ¡Paralelizar con control preciso es trivial!
ZIO.foreachParN(20)(urls) { url =>
for {
data <- load(url)
json <- parseToJson(data)
transformed <- transform(json)
} yield transformed
}
20/60
46. ZIO... Porque permite maximizar el Parelelismo en una
aplicación
// ¡Paralelizar con control preciso es trivial!
ZIO.foreachParN(20)(urls) { url =>
for {
data <- load(url)
json <- parseToJson(data)
transformed <- transform(json)
} yield transformed
}
20/60
48. ZIO... Porque permite maximizar el Parelelismo en una
aplicación
— Cada operador en ZIO que puede tener una versión
que se ejecuta en paralelo la tiene
21/60
49. ZIO... Porque permite maximizar el Parelelismo en una
aplicación
— Cada operador en ZIO que puede tener una versión
que se ejecuta en paralelo la tiene
— Estos operadores paralelos permiten controlar los
límites de concurrencia
21/60
50. ZIO... Por su poder para Programación Concurrente
// Varios workers consumiendo una cola,
// con back-pressuring automático
def startWorkers(n: Int, queue: Queue[Work]) = {
val worker = queue.take.flatMap(doWork).forever
val workers = List.fill(n)(worker)
ZIO.forkAll(workers)
}
22/60
51. ZIO... Por su poder para Programación Concurrente
// Varios workers consumiendo una cola,
// con back-pressuring automático
def startWorkers(n: Int, queue: Queue[Work]) = {
val worker = queue.take.flatMap(doWork).forever
val workers = List.fill(n)(worker)
ZIO.forkAll(workers)
}
22/60
52. ZIO... Por su poder para Programación Concurrente
// Varios workers consumiendo una cola,
// con back-pressuring automático
def startWorkers(n: Int, queue: Queue[Work]) = {
val worker = queue.take.flatMap(doWork).forever
val workers = List.fill(n)(worker)
ZIO.forkAll(workers)
}
22/60
53. ZIO... Por su poder para Programación Concurrente
// Varios workers consumiendo una cola,
// con back-pressuring automático
def startWorkers(n: Int, queue: Queue[Work]) = {
val worker = queue.take.flatMap(doWork).forever
val workers = List.fill(n)(worker)
ZIO.forkAll(workers)
}
22/60
54. ZIO... Por su poder para Programación Concurrente
// Varios workers consumiendo una cola,
// con back-pressuring automático
def startWorkers(n: Int, queue: Queue[Work]) = {
val worker = queue.take.flatMap(doWork).forever
val workers = List.fill(n)(worker)
ZIO.forkAll(workers)
}
22/60
55. ZIO... Por su poder para Programación Concurrente
// Varios workers consumiendo una cola,
// con back-pressuring automático
def startWorkers(n: Int, queue: Queue[Work]) = {
val worker = queue.take.flatMap(doWork).forever
val workers = List.fill(n)(worker)
ZIO.forkAll(workers)
}
22/60
56. ZIO... Por su poder para Programación Concurrente
// Hacer commit de transacciones condicionales sin Locks o
// Condition Variables, sin condiciones de carrera ni deadlocks:
def acquireConnection(available: TRef[List[Connection]], used: TRef[List[Connection]]) =
STM.atomically {
for {
// Si no se encuentra una conexión disponible, se hace un rollback de la transacción
// y se espera hasta que haya una disponible para reintentar
connection <- available.get.collect {
case head :: _ => head
}
_ <- available.update(_.drop(1))
_ <- used.update(connection :: _)
} yield connection
}
23/60
57. ZIO... Por su poder para Programación Concurrente
// Hacer commit de transacciones condicionales sin Locks o
// Condition Variables, sin condiciones de carrera ni deadlocks:
def acquireConnection(available: TRef[List[Connection]], used: TRef[List[Connection]]) =
STM.atomically {
for {
// Si no se encuentra una conexión disponible, se hace un rollback de la transacción
// y se espera hasta que haya una disponible para reintentar
connection <- available.get.collect {
case head :: _ => head
}
_ <- available.update(_.drop(1))
_ <- used.update(connection :: _)
} yield connection
}
23/60
58. ZIO... Por su poder para Programación Concurrente
// Hacer commit de transacciones condicionales sin Locks o
// Condition Variables, sin condiciones de carrera ni deadlocks:
def acquireConnection(available: TRef[List[Connection]], used: TRef[List[Connection]]) =
STM.atomically {
for {
// Si no se encuentra una conexión disponible, se hace un rollback de la transacción
// y se espera hasta que haya una disponible para reintentar
connection <- available.get.collect {
case head :: _ => head
}
_ <- available.update(_.drop(1))
_ <- used.update(connection :: _)
} yield connection
}
23/60
59. ZIO... Por su poder para Programación Concurrente
// Hacer commit de transacciones condicionales sin Locks o
// Condition Variables, sin condiciones de carrera ni deadlocks:
def acquireConnection(available: TRef[List[Connection]], used: TRef[List[Connection]]) =
STM.atomically {
for {
// Si no se encuentra una conexión disponible, se hace un rollback de la transacción
// y se espera hasta que haya una disponible para reintentar
connection <- available.get.collect {
case head :: _ => head
}
_ <- available.update(_.drop(1))
_ <- used.update(connection :: _)
} yield connection
}
23/60
60. ZIO... Por su poder para Programación Concurrente
// Hacer commit de transacciones condicionales sin Locks o
// Condition Variables, sin condiciones de carrera ni deadlocks:
def acquireConnection(available: TRef[List[Connection]], used: TRef[List[Connection]]) =
STM.atomically {
for {
// Si no se encuentra una conexión disponible, se hace un rollback de la transacción
// y se espera hasta que haya una disponible para reintentar
connection <- available.get.collect {
case head :: _ => head
}
_ <- available.update(_.drop(1))
_ <- used.update(connection :: _)
} yield connection
}
23/60
61. ZIO... Por su poder para Programación Concurrente
// Hacer commit de transacciones condicionales sin Locks o
// Condition Variables, sin condiciones de carrera ni deadlocks:
def acquireConnection(available: TRef[List[Connection]], used: TRef[List[Connection]]) =
STM.atomically {
for {
// Si no se encuentra una conexión disponible, se hace un rollback de la transacción
// y se espera hasta que haya una disponible para reintentar
connection <- available.get.collect {
case head :: _ => head
}
_ <- available.update(_.drop(1))
_ <- used.update(connection :: _)
} yield connection
}
23/60
62. ZIO... Por su poder para Programación Concurrente
// Hacer commit de transacciones condicionales sin Locks o
// Condition Variables, sin condiciones de carrera ni deadlocks:
def acquireConnection(available: TRef[List[Connection]], used: TRef[List[Connection]]) =
STM.atomically {
for {
// Si no se encuentra una conexión disponible, se hace un rollback de la transacción
// y se espera hasta que haya una disponible para reintentar
connection <- available.get.collect {
case head :: _ => head
}
_ <- available.update(_.drop(1))
_ <- used.update(connection :: _)
} yield connection
}
23/60
63. ZIO... Por su poder para Programación Concurrente
// Hacer commit de transacciones condicionales sin Locks o
// Condition Variables, sin condiciones de carrera ni deadlocks:
def acquireConnection(available: TRef[List[Connection]], used: TRef[List[Connection]]) =
STM.atomically {
for {
// Si no se encuentra una conexión disponible, se hace un rollback de la transacción
// y se espera hasta que haya una disponible para reintentar
connection <- available.get.collect {
case head :: _ => head
}
_ <- available.update(_.drop(1))
_ <- used.update(connection :: _)
} yield connection
}
23/60
64. ZIO... Porque permite eliminar leaks de recursos
// Empaquetamos la lógica de adquisición y liberación de un recurso usando Managed,
// eliminando cualquier posibilidad de leaks
val managedFile = Managed.make(open(file))(close(_))
// Modularidad: La lógica de uso de un recurso está separada de la lógica
// de adquisición y liberación del mismo
managedFile.use { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
24/60
65. ZIO... Porque permite eliminar leaks de recursos
// Empaquetamos la lógica de adquisición y liberación de un recurso usando Managed,
// eliminando cualquier posibilidad de leaks
val managedFile = Managed.make(open(file))(close(_))
// Modularidad: La lógica de uso de un recurso está separada de la lógica
// de adquisición y liberación del mismo
managedFile.use { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
24/60
66. ZIO... Porque permite eliminar leaks de recursos
// Empaquetamos la lógica de adquisición y liberación de un recurso usando Managed,
// eliminando cualquier posibilidad de leaks
val managedFile = Managed.make(open(file))(close(_))
// Modularidad: La lógica de uso de un recurso está separada de la lógica
// de adquisición y liberación del mismo
managedFile.use { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
24/60
67. ZIO... Porque permite eliminar leaks de recursos
// Empaquetamos la lógica de adquisición y liberación de un recurso usando Managed,
// eliminando cualquier posibilidad de leaks
val managedFile = Managed.make(open(file))(close(_))
// Modularidad: La lógica de uso de un recurso está separada de la lógica
// de adquisición y liberación del mismo
managedFile.use { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
24/60
68. ZIO... Porque permite eliminar leaks de recursos
// Empaquetamos la lógica de adquisición y liberación de un recurso usando Managed,
// eliminando cualquier posibilidad de leaks
val managedFile = Managed.make(open(file))(close(_))
// Modularidad: La lógica de uso de un recurso está separada de la lógica
// de adquisición y liberación del mismo
managedFile.use { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
24/60
69. ZIO... Porque permite eliminar leaks de recursos
// Combinar varios ZManaged en uno solo
val managedFiles = ZManaged.foreach(files){ file =>
Managed.make(open(file))(close(_))
}
// Todos los archivos se abren y se cierran al mismo tiempo,
// de forma automática
managedFiles.use { resources =>
ZIO.foreach(resources) { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
}
25/60
70. ZIO... Porque permite eliminar leaks de recursos
// Combinar varios ZManaged en uno solo
val managedFiles = ZManaged.foreach(files){ file =>
Managed.make(open(file))(close(_))
}
// Todos los archivos se abren y se cierran al mismo tiempo,
// de forma automática
managedFiles.use { resources =>
ZIO.foreach(resources) { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
}
25/60
71. ZIO... Porque permite eliminar leaks de recursos
// Combinar varios ZManaged en uno solo
val managedFiles = ZManaged.foreach(files){ file =>
Managed.make(open(file))(close(_))
}
// Todos los archivos se abren y se cierran al mismo tiempo,
// de forma automática
managedFiles.use { resources =>
ZIO.foreach(resources) { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
}
25/60
72. ZIO... Porque permite eliminar leaks de recursos
// Combinar varios ZManaged en uno solo
val managedFiles = ZManaged.foreach(files){ file =>
Managed.make(open(file))(close(_))
}
// Todos los archivos se abren y se cierran al mismo tiempo,
// de forma automática
managedFiles.use { resources =>
ZIO.foreach(resources) { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
}
25/60
73. ZIO... Porque permite eliminar leaks de recursos
// Combinar varios ZManaged en uno solo
val managedFiles = ZManaged.foreach(files){ file =>
Managed.make(open(file))(close(_))
}
// Todos los archivos se abren y se cierran al mismo tiempo,
// de forma automática
managedFiles.use { resources =>
ZIO.foreach(resources) { resource =>
(for {
data <- read(resource)
_ <- aggregateData(data)
} yield ()).forever
}
}
25/60
74. ZIO... Porque es Globalmente Eficiente,
automáticamente
val geoLookup = geoIpService.lookup(ipAddress)
val dbLookup = userRepo.getProfile(userId).map(_.location.toLatLong)
// Hacer que dos efectos compitan en paralelo, cancelando el perdedor
val fastest = geoLookup.race(dbLookup)
26/60
75. ZIO... Porque es Globalmente Eficiente,
automáticamente
val geoLookup = geoIpService.lookup(ipAddress)
val dbLookup = userRepo.getProfile(userId).map(_.location.toLatLong)
// Hacer que dos efectos compitan en paralelo, cancelando el perdedor
val fastest = geoLookup.race(dbLookup)
26/60
76. ZIO... Porque es Globalmente Eficiente,
automáticamente
val geoLookup = geoIpService.lookup(ipAddress)
val dbLookup = userRepo.getProfile(userId).map(_.location.toLatLong)
// Hacer que dos efectos compitan en paralelo, cancelando el perdedor
val fastest = geoLookup.race(dbLookup)
26/60
77. ZIO... Porque es Globalmente Eficiente,
automáticamente
val geoLookup = geoIpService.lookup(ipAddress)
val dbLookup = userRepo.getProfile(userId).map(_.location.toLatLong)
// Hacer que dos efectos compitan en paralelo, cancelando el perdedor
val fastest = geoLookup.race(dbLookup)
26/60
78. ZIO... Porque es Globalmente Eficiente,
automáticamente
val geoLookup = geoIpService.lookup(ipAddress)
val dbLookup = userRepo.getProfile(userId).map(_.location.toLatLong)
// Hacer que dos efectos corran en paralelo,
// Si uno de ellos falla, el otro es automáticamente interrumpido
val fastest = geoLookup.zipPar(dbLookup)
27/60
79. ZIO... Porque es Globalmente Eficiente,
automáticamente
val geoLookup = geoIpService.lookup(ipAddress)
val dbLookup = userRepo.getProfile(userId).map(_.location.toLatLong)
// Hacer que dos efectos corran en paralelo,
// Si uno de ellos falla, el otro es automáticamente interrumpido
val fastest = geoLookup.zipPar(dbLookup)
27/60
80. ZIO... Porque es Globalmente Eficiente,
automáticamente
val geoLookup = geoIpService.lookup(ipAddress)
val dbLookup = userRepo.getProfile(userId).map(_.location.toLatLong)
// Hacer que dos efectos corran en paralelo,
// Si uno de ellos falla, el otro es automáticamente interrumpido
val fastest = geoLookup.zipPar(dbLookup)
27/60
81. ZIO... Porque es Globalmente Eficiente,
automáticamente
val geoLookup = geoIpService.lookup(ipAddress)
val dbLookup = userRepo.getProfile(userId).map(_.location.toLatLong)
// Hacer que dos efectos corran en paralelo,
// Si uno de ellos falla, el otro es automáticamente interrumpido
val fastest = geoLookup.zipPar(dbLookup)
27/60
82. ZIO... Porque es Globalmente Eficiente,
automáticamente
val slowDbQuery = userRepo.getProfile(userId)
// Cancelar efectos que se ejecutan lentamente, después de un timeout determinado
slowDbQuery.timeout(60.seconds)
28/60
83. ZIO... Porque es Globalmente Eficiente,
automáticamente
val slowDbQuery = userRepo.getProfile(userId)
// Cancelar efectos que se ejecutan lentamente, después de un timeout determinado
slowDbQuery.timeout(60.seconds)
28/60
84. ZIO... Porque es Globalmente Eficiente,
automáticamente
val slowDbQuery = userRepo.getProfile(userId)
// Cancelar efectos que se ejecutan lentamente, después de un timeout determinado
slowDbQuery.timeout(60.seconds)
28/60
85. ZIO... Porque es Globalmente Eficiente,
automáticamente
val slowDbQuery = userRepo.getProfile(userId)
// Cancelar efectos que se ejecutan lentamente, después de un timeout determinado
slowDbQuery.timeout(60.seconds)
28/60
86. ZIO... Porque permite operar sobre Streams infinitos de
datos
// ZIO Streams nos permite construir pipelines complejos
// que operen sobre flujos de datos posiblemente infinitos,
// de forma declarativa, concurrente, leak-free y usando
// un espacio constante de memoria.
val wordCount =
ZStream
.fromInputStream(Files.newInputStream(path))
.transduce(ZTransducer.utf8Decode)
.transduce(ZTransducer.splitOn(" "))
.run(ZSink.count)
29/60
87. ZIO... Porque permite operar sobre Streams infinitos de
datos
// ZIO Streams nos permite construir pipelines complejos
// que operen sobre flujos de datos posiblemente infinitos,
// de forma declarativa, concurrente, leak-free y usando
// un espacio constante de memoria.
val wordCount =
ZStream
.fromInputStream(Files.newInputStream(path))
.transduce(ZTransducer.utf8Decode)
.transduce(ZTransducer.splitOn(" "))
.run(ZSink.count)
29/60
88. ZIO... Porque permite operar sobre Streams infinitos de
datos
// ZIO Streams nos permite construir pipelines complejos
// que operen sobre flujos de datos posiblemente infinitos,
// de forma declarativa, concurrente, leak-free y usando
// un espacio constante de memoria.
val wordCount =
ZStream
.fromInputStream(Files.newInputStream(path))
.transduce(ZTransducer.utf8Decode)
.transduce(ZTransducer.splitOn(" "))
.run(ZSink.count)
29/60
89. ZIO... Porque permite operar sobre Streams infinitos de
datos
// ZIO Streams nos permite construir pipelines complejos
// que operen sobre flujos de datos posiblemente infinitos,
// de forma declarativa, concurrente, leak-free y usando
// un espacio constante de memoria.
val wordCount =
ZStream
.fromInputStream(Files.newInputStream(path))
.transduce(ZTransducer.utf8Decode)
.transduce(ZTransducer.splitOn(" "))
.run(ZSink.count)
29/60
90. ZIO... Porque permite operar sobre Streams infinitos de
datos
// ZIO Streams nos permite construir pipelines complejos
// que operen sobre flujos de datos posiblemente infinitos,
// de forma declarativa, concurrente, leak-free y usando
// un espacio constante de memoria.
val wordCount =
ZStream
.fromInputStream(Files.newInputStream(path))
.transduce(ZTransducer.utf8Decode)
.transduce(ZTransducer.splitOn(" "))
.run(ZSink.count)
29/60
91. ZIO... Porque permite operar sobre Streams infinitos de
datos
// ZIO Streams nos permite construir pipelines complejos
// que operen sobre flujos de datos posiblemente infinitos,
// de forma declarativa, concurrente, leak-free y usando
// un espacio constante de memoria.
val wordCount =
ZStream
.fromInputStream(Files.newInputStream(path))
.transduce(ZTransducer.utf8Decode)
.transduce(ZTransducer.splitOn(" "))
.run(ZSink.count)
29/60
92. ZIO... Porque nos permite crear aplicaciones fáciles de
testear
// ZIO permite alta testabilidad a través del ZIO Environment, el cual hace que sea fácil para los desarrolladores
// seguir buenas prácticas de Programación Orientada a Objetos, por ejemplo:
// "Codificar contra interfaces, no implementaciones".
// Además, ZIO nos permite escribir tests que sean rápidos y determinísticos,
// incluso para aplicaciones interactivas, no determinísticas
val program: ZIO[Has[Clock] with Has[Console], IOException, Unit] =
for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStrLn(s"I will wait ${name.length} seconds, $name")
_ <- ZIO.sleep(name.length.seconds)
} yield ()
// testServices contiene implementaciones de prueba para Clock y Console
val deterministicResult = program.provideLayer(testServices)
30/60
93. ZIO... Porque nos permite crear aplicaciones fáciles de
testear
// ZIO permite alta testabilidad a través del ZIO Environment, el cual hace que sea fácil para los desarrolladores
// seguir buenas prácticas de Programación Orientada a Objetos, por ejemplo:
// "Codificar contra interfaces, no implementaciones".
// Además, ZIO nos permite escribir tests que sean rápidos y determinísticos,
// incluso para aplicaciones interactivas, no determinísticas
val program: ZIO[Has[Clock] with Has[Console], IOException, Unit] =
for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStrLn(s"I will wait ${name.length} seconds, $name")
_ <- ZIO.sleep(name.length.seconds)
} yield ()
// testServices contiene implementaciones de prueba para Clock y Console
val deterministicResult = program.provideLayer(testServices)
30/60
94. ZIO... Porque nos permite crear aplicaciones fáciles de
testear
// ZIO permite alta testabilidad a través del ZIO Environment, el cual hace que sea fácil para los desarrolladores
// seguir buenas prácticas de Programación Orientada a Objetos, por ejemplo:
// "Codificar contra interfaces, no implementaciones".
// Además, ZIO nos permite escribir tests que sean rápidos y determinísticos,
// incluso para aplicaciones interactivas, no determinísticas
val program: ZIO[Has[Clock] with Has[Console], IOException, Unit] =
for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStrLn(s"I will wait ${name.length} seconds, $name")
_ <- ZIO.sleep(name.length.seconds)
} yield ()
// testServices contiene implementaciones de prueba para Clock y Console
val deterministicResult = program.provideLayer(testServices)
30/60
95. ZIO... Porque nos permite crear aplicaciones fáciles de
testear
// ZIO permite alta testabilidad a través del ZIO Environment, el cual hace que sea fácil para los desarrolladores
// seguir buenas prácticas de Programación Orientada a Objetos, por ejemplo:
// "Codificar contra interfaces, no implementaciones".
// Además, ZIO nos permite escribir tests que sean rápidos y determinísticos,
// incluso para aplicaciones interactivas, no determinísticas
val program: ZIO[Has[Clock] with Has[Console], IOException, Unit] =
for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStrLn(s"I will wait ${name.length} seconds, $name")
_ <- ZIO.sleep(name.length.seconds)
} yield ()
// testServices contiene implementaciones de prueba para Clock y Console
val deterministicResult = program.provideLayer(testServices)
30/60
96. ZIO... Porque nos permite crear aplicaciones fáciles de
testear
// ZIO permite alta testabilidad a través del ZIO Environment, el cual hace que sea fácil para los desarrolladores
// seguir buenas prácticas de Programación Orientada a Objetos, por ejemplo:
// "Codificar contra interfaces, no implementaciones".
// Además, ZIO nos permite escribir tests que sean rápidos y determinísticos,
// incluso para aplicaciones interactivas, no determinísticas
val program: ZIO[Has[Clock] with Has[Console], IOException, Unit] =
for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStrLn(s"I will wait ${name.length} seconds, $name")
_ <- ZIO.sleep(name.length.seconds)
} yield ()
// testServices contiene implementaciones de prueba para Clock y Console
val deterministicResult = program.provideLayer(testServices)
30/60
97. ZIO... Porque nos permite crear aplicaciones resilientes
// Deja que el compilador te diga qué puede fallar, y por qué
val result: IO[RequestException, Result] = callFlakyApi(request)
// ZIO aprovecha al máximo el poder del compilador de Scala,
// para que guiados por él podamos construir aplicaciones resilientes
// Por ejemplo, ZIO nos permite introducir reintentos que se ejecuten
// de acuerdo a un Schedule específico
val retryPolicy =
(Schedule.exponential(10.millis).whileOutput(_ < 1.second) andThen
Schedule.spaced(60.seconds)
) && Schedule.recurs(100)
val robustResult: IO[RequestException, Result] = result.retry(retryPolicy)
// Deja que el compilador te diga qué NO puede fallar
val infallible: IO[Nothing, Result] = robustResult.catchAll(_ => fallback)
31/60
98. ZIO... Porque nos permite crear aplicaciones resilientes
// Deja que el compilador te diga qué puede fallar, y por qué
val result: IO[RequestException, Result] = callFlakyApi(request)
// ZIO aprovecha al máximo el poder del compilador de Scala,
// para que guiados por él podamos construir aplicaciones resilientes
// Por ejemplo, ZIO nos permite introducir reintentos que se ejecuten
// de acuerdo a un Schedule específico
val retryPolicy =
(Schedule.exponential(10.millis).whileOutput(_ < 1.second) andThen
Schedule.spaced(60.seconds)
) && Schedule.recurs(100)
val robustResult: IO[RequestException, Result] = result.retry(retryPolicy)
// Deja que el compilador te diga qué NO puede fallar
val infallible: IO[Nothing, Result] = robustResult.catchAll(_ => fallback)
31/60
99. ZIO... Porque nos permite crear aplicaciones resilientes
// Deja que el compilador te diga qué puede fallar, y por qué
val result: IO[RequestException, Result] = callFlakyApi(request)
// ZIO aprovecha al máximo el poder del compilador de Scala,
// para que guiados por él podamos construir aplicaciones resilientes
// Por ejemplo, ZIO nos permite introducir reintentos que se ejecuten
// de acuerdo a un Schedule específico
val retryPolicy =
(Schedule.exponential(10.millis).whileOutput(_ < 1.second) andThen
Schedule.spaced(60.seconds)
) && Schedule.recurs(100)
val robustResult: IO[RequestException, Result] = result.retry(retryPolicy)
// Deja que el compilador te diga qué NO puede fallar
val infallible: IO[Nothing, Result] = robustResult.catchAll(_ => fallback)
31/60
100. ZIO... Porque nos permite crear aplicaciones resilientes
// Deja que el compilador te diga qué puede fallar, y por qué
val result: IO[RequestException, Result] = callFlakyApi(request)
// ZIO aprovecha al máximo el poder del compilador de Scala,
// para que guiados por él podamos construir aplicaciones resilientes
// Por ejemplo, ZIO nos permite introducir reintentos que se ejecuten
// de acuerdo a un Schedule específico
val retryPolicy =
(Schedule.exponential(10.millis).whileOutput(_ < 1.second) andThen
Schedule.spaced(60.seconds)
) && Schedule.recurs(100)
val robustResult: IO[RequestException, Result] = result.retry(retryPolicy)
// Deja que el compilador te diga qué NO puede fallar
val infallible: IO[Nothing, Result] = robustResult.catchAll(_ => fallback)
31/60
101. ZIO... Porque nos permite crear aplicaciones resilientes
// Deja que el compilador te diga qué puede fallar, y por qué
val result: IO[RequestException, Result] = callFlakyApi(request)
// ZIO aprovecha al máximo el poder del compilador de Scala,
// para que guiados por él podamos construir aplicaciones resilientes
// Por ejemplo, ZIO nos permite introducir reintentos que se ejecuten
// de acuerdo a un Schedule específico
val retryPolicy =
(Schedule.exponential(10.millis).whileOutput(_ < 1.second) andThen
Schedule.spaced(60.seconds)
) && Schedule.recurs(100)
val robustResult: IO[RequestException, Result] = result.retry(retryPolicy)
// Deja que el compilador te diga qué NO puede fallar
val infallible: IO[Nothing, Result] = robustResult.catchAll(_ => fallback)
31/60
102. ZIO... Porque nos permite crear aplicaciones resilientes
// Deja que el compilador te diga qué puede fallar, y por qué
val result: IO[RequestException, Result] = callFlakyApi(request)
// ZIO aprovecha al máximo el poder del compilador de Scala,
// para que guiados por él podamos construir aplicaciones resilientes
// Por ejemplo, ZIO nos permite introducir reintentos que se ejecuten
// de acuerdo a un Schedule específico
val retryPolicy =
(Schedule.exponential(10.millis).whileOutput(_ < 1.second) andThen
Schedule.spaced(60.seconds)
) && Schedule.recurs(100)
val robustResult: IO[RequestException, Result] = result.retry(retryPolicy)
// Deja que el compilador te diga qué NO puede fallar
val infallible: IO[Nothing, Result] = robustResult.catchAll(_ => fallback)
31/60
103. ZIO... Porque nos permite crear aplicaciones resilientes
// Deja que el compilador te diga qué puede fallar, y por qué
val result: IO[RequestException, Result] = callFlakyApi(request)
// ZIO aprovecha al máximo el poder del compilador de Scala,
// para que guiados por él podamos construir aplicaciones resilientes
// Por ejemplo, ZIO nos permite introducir reintentos que se ejecuten
// de acuerdo a un Schedule específico
val retryPolicy =
(Schedule.exponential(10.millis).whileOutput(_ < 1.second) andThen
Schedule.spaced(60.seconds)
) && Schedule.recurs(100)
val robustResult: IO[RequestException, Result] = result.retry(retryPolicy)
// Deja que el compilador te diga qué NO puede fallar
val infallible: IO[Nothing, Result] = robustResult.catchAll(_ => fallback)
31/60
105. ZIO... Porque es altamente Composicional
val managedData = Managed.make(open(url))(close(_))
managedData.use { data =>
searchBreadth(data)
}
33/60
116. ZIO... Porque es altamente Composicional
val policy = Schedule.recurs(100)
ZIO.foreachParN(20)(urls) { url =>
val managedData = Managed.make(open(url))(close(_))
val robustData = managedData.retry(policy)
robustData.use { data =>
searchBreadth(data)
}
}
41/60
117. ZIO... Porque es altamente Composicional
val policy = Schedule.recurs(100)
ZIO.foreachParN(20)(urls) { url =>
val managedData = Managed.make(open(url))(close(_))
val robustData = managedData.retry(policy)
robustData.use { data =>
searchBreadth(data)
}
}
41/60
118. ZIO... Porque es altamente Composicional
val policy = Schedule.recurs(100)
ZIO.foreachParN(20)(urls) { url =>
val managedData = Managed.make(open(url))(close(_))
val robustData = managedData.retry(policy)
robustData.use { data =>
searchBreadth(data)
}
}
41/60
140. Mejoras que serán introducidas
en ZIO 2.0
— Profiler incorporado
54/60
141. Mejoras que serán introducidas
en ZIO 2.0
— Profiler incorporado
— Mejor execution tracing, con
prácticamente cero overhead
54/60
142. Mejoras que serán introducidas
en ZIO 2.0
— Profiler incorporado
— Mejor execution tracing, con
prácticamente cero overhead
— Métricas incorporadas, con
soporte por defecto para:
54/60
143. Mejoras que serán introducidas
en ZIO 2.0
— Profiler incorporado
— Mejor execution tracing, con
prácticamente cero overhead
— Métricas incorporadas, con
soporte por defecto para:
— Datadog
54/60
144. Mejoras que serán introducidas
en ZIO 2.0
— Profiler incorporado
— Mejor execution tracing, con
prácticamente cero overhead
— Métricas incorporadas, con
soporte por defecto para:
— Datadog
— StatsD
54/60
145. Mejoras que serán introducidas
en ZIO 2.0
— Profiler incorporado
— Mejor execution tracing, con
prácticamente cero overhead
— Métricas incorporadas, con
soporte por defecto para:
— Datadog
— StatsD
— Prometheus
54/60
146. Mejoras que serán introducidas
en ZIO 2.0
— Profiler incorporado
— Mejor execution tracing, con
prácticamente cero overhead
— Métricas incorporadas, con
soporte por defecto para:
— Datadog
— StatsD
— Prometheus
— New Relic
54/60
168. Dónde encontrar más info
acerca de ZIO
— Página oficial de ZIO
— ZIO en GitHub
58/60
169. Dónde encontrar más info
acerca de ZIO
— Página oficial de ZIO
— ZIO en GitHub
— Zionomicon
58/60
170. Dónde encontrar más info
acerca de ZIO
— Página oficial de ZIO
— ZIO en GitHub
— Zionomicon
— "The ZIO of the Future", charla
por John De Goes (autor de
ZIO)
58/60
172. Dónde encontrar más info
acerca de ZIO
— Introducción a la
Programación con Efectos
Funcionales usando ZIO
59/60
173. Dónde encontrar más info
acerca de ZIO
— Introducción a la
Programación con Efectos
Funcionales usando ZIO
— Functional Programming 101
with Scala and ZIO
59/60
174. Dónde encontrar más info
acerca de ZIO
— Introducción a la
Programación con Efectos
Funcionales usando ZIO
— Functional Programming 101
with Scala and ZIO
— Mastering Modularity in ZIO
with ZLayer
59/60
175. Dónde encontrar más info
acerca de ZIO
— Introducción a la
Programación con Efectos
Funcionales usando ZIO
— Functional Programming 101
with Scala and ZIO
— Mastering Modularity in ZIO
with ZLayer
— How to write a (completely
lock-free) concurrent LRU
Cache with ZIO STM
59/60