How can pure functionality take your project to a whole new level? Now you have a chance to get insider information from professionals with invaluable knowledge resulting from years of experience.
We asked 7 ZIO and Scala developers from various companies (including Univalence, PPC Samurai, MATECHS, CreditSCRIPT, rudder.io) a few questions about ZIO. Now we want to share with you the results of these interviews.
- What do you think about ZIO’s typed errors? How do you think they help to write better applications?
- What do you think the advantages of ZIO’s Fibers over Threads are, when writing concurrent applications?
- Do you think ZIO helps you to make code more testable? Why?
- What do you think about ZIO’s interruption model and how does it help with achieving global application efficiency?
- What’s your experience with ZManaged? What problems do you think it helps solve?
- What’s your experience with ZLayers? What problems do you think it helps solve?
- Why would you say ZIO is preferable to other similar libraries?
- Do you have experience with ZStreams? What problems do you think it helps solve?
Introducing ZIO to commercial projects
The Scala language combines the best of both the functional and object-oriented programming worlds. Within the Scala ecosystem, there are Scala libraries such as ZIO — which is the main topic of this article. Scalac as a Backend Development Company specializes in making type-safe, composable, asynchronous, concurrent programming for ZIO Scala projects. We help our clients implement ZIO in commercial projects — e.g. Fugo. We have sponsored events such as the ZIO Hackaton, and Functional Scala. At Scalac we have delivered plenty of talks about ZIO by Scala developers, at conferences and meetups such as Scale by the Bay, Functional World, and Functional Tricity.
But today it is not Scalac who will be preaching the advantages of this Scala library. It is going to be experienced professionals in this field telling you why a Scala library such as ZIO could be the perfect choice for creating your projects.
We’ve already tackled the “Why ZIO” topic in Why Developers Should Pay Attention to ZIO in 2021 article where we mention companies like Apple, DHL, and Wix.com that use ZIO in their companies. So don’t forget to check it out as well!
Who has shared their experiences with ZIO?
- Dean Povey Chief Technology Officer at adpulse.io and PPC Samurai
- Michael Arnaldi Technology Maniac — Speaker — CEO at MATECHS — CTO at CreditSCRIPT
- François Sarradin CTO at Univalence
- Francois Armand CTO at rudder.io
- Ruurtjan Pul Data Engineer
- Loïc Descotte Functional Programmer, Software Architect
- Jerome Samson Senior Full Stack Developer | Technical Lead | Scala | ZIO |
Q&A with ZIO experts
What do you think about ZIO’s typed errors? How do you think they help to write better applications?
Dean Povey:
This is probably one of the nicest advantages of ZIO. You can use a specific error type and ensure that consumers know exactly what errors they need to handle. The ability to know that you have handled any errors in an effect or that the effect cannot fail is also helpful.
Michael Arnaldi:
Having typed errors is fundamental in order to write code that takes care of handling the edge cases, if you don’t have type information when calling a specific effect you cannot know what you may need to handle.
François Sarradin :
On the one hand, the developer is more aware that any processes may fail, unless explicitly indicated with Nothing (or by using an unfailing type like UIO or URIO). This is similar to the idea of exceptions in Java that you have to declare in the method signature, to manage error. This feature is good. But developers regularly bypass it. With ZIO and the type management in Scala, you can explicitly declare a process returning an exception, or do the same implicitly (with the type Task), or even use your own type to represent errors, and have pure business error representation.
On the other hand, as the ZIO type is rather flat (in comparison to MTL approach), making the operations on ZIO more accessible to developers. Flat structures are usually more adapted if you want a better understanding of the code.
What do you think the advantages of ZIO’s Fibers over Threads are, when writing concurrent applications?
Michael Arnaldi:
Fibers are extremely lightweight compared to threads and in ZIO they provide an even richer API and set of capabilities. One of the huge innovations that ZIO introduces is the concept of a fork scope and a supervision model that is able to preserve the fork-join identity, additionally, ZIO’s runtime is very efficient in scheduling fibers across threads and it’s getting better and better with ZIO 2.0.
François Sarradin:
I tend to think that ZIO’s Fiber approach is good. I perceive Fiber as a high-level abstraction for parallel computing, that comes with more accessible representations and operations. This helps Scala developers to better handle concurrency. (…) ZIO’s Fiber comes with this strong FP layer like immutability, predictability, referential transparency…, and a set of functions that are more or less similar to functions that manage other kinds of type. That helps you to have a better understanding of your code. It comes with fewer surprises (side effects, race condition, and so on). This gives you more confidence in your day-to-day work.
Do you think ZIO helps you to make code more testable? Why?
Dean Povey:
Yes but only in a small way. Mainly due to Clock and Random being easy to mock. Otherwise using the module 2.0 pattern code ends up looking like it did without ZIO.
Michael Arnaldi:
ZIO introduced a third type of parameter to manage the dynamic environment, with the environment capabilities ZIO has developed a fully-fledged dependency injection mechanism that enables you to easily construct trees of dependencies for your application. The same capability can be used to mock services in test contexts.
Francois Armand:
(…) composition (in the FP meaning, ie being able to split a big problem into smaller ones, solve (and prove they are solved because of properties of the solution) each small problem, compose back small solutions into a bigger one that KEEPS the properties you checked) is a key part of testability. By helping us to split big problems as we need (not only sequentially, or by object responsibility, but as really we need it, even if it implies concurrency, distributed states, complex error handling on asynchronous things, etc), ZIO helps us make smaller parts from our big programs, and so makes them easier to unit tests.
What do you think about ZIO’s interruption model and how does it help with achieving global application efficiency?
Michael Arnaldi:
ZIO’s interruption model is not only needed for efficiency, for that it is good but more importantly it is a core part of application design for correctness, in fact when you run your application you always want to respond properly to process interruption signals. Here, by reacting properly I mean doing the hard thing, graceful shutdown of everything that is running (that may be millions of fibers) asynchronously and in the correct order (for example if you have an effect that is performing a database op in a transaction, first the effect should be interrupted then the transaction rolled back and finally the connection to the database closed, all of this is out-of-the-box with ZIO).
Francois Armand:
A big question. The fiber model is very nice, it allows splitting of problems as a best fit for the problem solution, not as it is technically possible given the reality of resources (threads) on the OS. Typically, it’s generally much simpler to think about a process on 10,000 servers as 10,000 time the process on one server — but thread pool are not meant to do that, especially if the process has steps like “do these 100 things (semantically) in parallel, go to next step when one of these conditions arise”. Plus, ZIO debuggability (fiber dump) is exceptional, making it actually easy to understand what went wrong in an async/concurrent environment, which is such a relief and an upgrade compared to whatever I know elsewhere.
An important characteristic of ZIO is compositionality, how do you think that helps when writing real-world applications?
Ruurtjan Pul :
Compositionality has been one of the main reasons to choose ZIO for the backend of https://www.nslookup.io. Many of the API calls require blocking network calls, some of which can be executed in parallel, others depend on one or more of these calls. Constructing this graph of run-time dependencies, and working with their run-time results is where ZIO’s compositionality really shines.
Michael Arnaldi:
Compositionality is not unique to ZIO, it is the core essence of functional programming. In fact all of what we do in fp is to isolate behaviours in an orthogonal manner to enable higher composition. ZIO is very good at this and especially the idea to have a single base effect type that is contravariant in R (the environment) has been a design choice that resulted in an extremely well-composable system of modules.
Francois Armand:
I think I already answered that, but to sum up: being able to split big problems into smaller ones, solve the small ones proving that some properties hold, then compose back the small solutions to solve the big problem BEING ASSURED that the properties are kept — even if the composition implies effects, concurrency, asynchronicity, etc.
To sum up the benefits
Thanks to ZIO, we are able to split a problem into smaller parts and put them back together to build large applications. This is an essential concept and it allows us to build software, no matter the amount of complexity involved.
To find out how great ZIO is for modularity, it’s to make time to share the secrets about specific data types and their applications.
The Power of ZManaged, ZLayers and ZStreams
What’s your experience with ZManaged? What problems do you think it helps solve?
Michael Arnaldi:
ZManaged is a type that focuses on the composition of managed resources; you might think of a managed resource as the pair of acquire/release that you would have in a bracket operation. Isolating the focus on the acquire-release logic enables ZIO to provide a rich set of APIs for the composition of resources. Using managed, you can represent for example services that are dependent on connection pools that require safe cleanup.
Dean Povey:
We use it whenever we need a resource that has to be cleaned up. It avoids having to remember to add a try-finally and is also nicely composable.
Francois Armand:
Our experience is great :) We use it broadly to cleanly manage closing of disposable resources without even having to think about it, which is a relief, because that problem is damn hard and I really don’t want to have my team spend countless hours on things like “we are leaking file descriptors and it kills the app/db connection/whatever”, which adds exactly 0 value to our product and is extremely complicated to get right in the concurrent/async env. And rudder does a lot of that concurrent/async work, with file systems and DB and etc.
The case for ZManaged is actually the same for all other concurrent primitives given by ZIO in the context of effects. These problems are hard and likely need to be handled by your more experienced dev who should spend time elsewhere; they rarely add value to your product directly (ie your product business is not “managing concurrency”, it’s more “build an MMO game”, or whatever); but they create massively impacting bugs, even showstopper ones (so you can’t just ignore them). I’m very glad I don’t have to spend more time thinking about whether my file input stream is cleanly closed in all possible cases of concurrent exceptions.
We’ve already tackled the “Why ZIO” topic in Why Developers Should Pay Attention to ZIO in 2021 article where we mention companies like Apple, DHL, and Wix.com that use ZIO in their companies. So don’t forget to check it out as well!
What’s your experience with ZLayers? What problems do you think it helps solve?
Loïc Descotte:
I like the typed dependency injection for IO environments (using Zlayers). There is a type safe guarantee that your tests do not call real-world services for example. For ZLayers, I like the type safe approach of dependency injection, and the fact that you can see in each IO type definition which outside service it’s using
Ruurtjan Pul:
When ZIO was pre 1.0.0, ZLayers were handy, but kind of a hassle to work with. The composition of layers is now a lot more convenient in ZIO 1.x. It can even be automated by Kit’s Zio magic (https://github.com/kitlangton/zio-magic), but doesn’t work with Scala 3, due to its reliance on macros.
The hope is that ZIO 2 will make ZLayers more convenient to work with and debug. Until then, you’ll have to wire them up manually. They still provide a nice way of dependency injection, though. So I’ll keep using it in my applications.
Francois Armand:
The ZLayer concept is absolutely wonderful, and I’ve dreamed about a principled and composable IoC framework for the scala ecosystem since 2006. I only had to wait 15 years to get it, especially since ZIO 2.0 is cleaning a lot of the complicated parts of using Zlayer, and best practices start to come. Still, the price for us is extremely high, and I’m not sure we will be able to pay for it in Rudder. We will need to introduce ZLayer bit by bit, which is not simple.
Jerome Samson:
I use ZLayers a lot. It is the ideal replacement for the classic dependency injection mechanism. ZLayers compose really well, that helps you to build the dependency graph of your app easily.
Do you have experience with ZStreams? What problems do you think it helps solve?
François Sarradin:
Currently, we have used ZStreams and ZManaged to help create small jobs with a Kafka producer exposing data from files or to connect Kafka and Cassandra for one-shot tasks. ZStreams is perfect for such use cases. It helps to synchronize resources altogether and potentially apply some transformations to data. Moreover, the approach is lighter than Kafka Streams. Kafka Streams is great to develop fully scalable data transformation services. But it is not really intended for one-shot jobs with sources or sinks other than a Kafka topic. Kafka Connect could do the job, but it is intended to continuously transfer data between the Kafka world and other kinds of data repository, and not really for one-shot processing.
Dean Povey:
We use ZStream extensively in our code base. We are moving from a legacy application that has to run on expensive large RAM compute instances (our JVMs have 96Gb of the pile!) due to the amount of data it processes in memory. ZStream gives a data structure that makes it easy to process these jobs in chunks, reducing our memory overheads and avoiding pipeline stalls as we stream this data from over the network. There are some nice abstractions such as the ZTransducer which allow reusability of stream processing pipelines that work really well. Pull-based streaming solutions have always held an appeal for us — and we have used fs2 in previous projects. However, ZStream is nicer to use than fs2.
If the stories told so far have not yet fully convinced you to choose ZIO and learn more about it, maybe you want to know why of all the other function libraries ZIO has been the choice of many? The next step, is to ask this essential question:
Why would you say ZIO is preferable to other similar libraries?
Dean Povey:
I have used Monix, Cats IO and fs2 in the past (and written a fair amount of concurrent Java code) and I am ZIO all the way. The type system dependency injection is a killer feature, and the rich and emerging ecosystem for ZIO also gives us confidence that ZIO is here to stay. Typed errors are also really nice and create confidence in the correctness of our programs. ZStreams are a well-done pull-based streaming abstraction and make it possible to quickly build high-performing stream processing applications without too much fuss.
We also love the focus on performance and practicality in ZIO. The core team is constantly striving to reduce the overheads and to make the scala library easy and more obvious to use.
François Sarradin
On my current project, we are 4 developers. As said before, we chose to use ZIO from the start. We should also from time to time code with frameworks using libraries like Typelevel’s Cats, http4s, circe… What I see, is that the developers from my team are more comfortable with ZIO. And it is also the feedback that the developers give me. They from time to time need my help, but in a view to learning more.
To manipulate types with F[_] might be a good thing if you are a lib author, who wants generic functions. But, this leads to complicated types, it is almost hard to grasp for most developers, and it goes beyond the needs of daily development. I do not say that ZIO comes with no need to learn. But with a minimum mastering, it helps to cover your needs.
It is also easy to design with ZIO. Like any other libraries based on FP principles, the ZIO approach is scalable: what you design with ZIO at a small scale in a REPL should have the same behavior at a higher scale in your application (with some differences in terms of technical behavior due to machine limitations). But there you manipulate effective functions, or programs. This helps to design and build your application bit by bit while controlling the behavior of each part and of the whole composition altogether.
Jerome Samson:
Because ZIO is a developer-friendly scala library, it’s also ideal for newcomers to scala. They do not need to understand any concept from Category theory to get the most out of it (Like cats effect).
Learn and fall in love with ZIO — a list of our free resources
This is not the end of today’s journey. Here are some additional resources from Scala developers, and Scalac’s insights for you, that will help you to achieve your goals in a functional way — with the ZIO Scala library.
Ebooks & Articles
- Introduction to Programming with ZIO Functional Effects
- Introducción a la Programación con Efectos Funcionales usando ZIO
- Mastering Modularity in ZIO with Zlayer (updated to ZIO 1.0.10)
- Improve your focus with ZIO Optics
- Streaming microservices with ZIO and Kafka
- Build your own Kafka in ZIO — Queues & Fibers
Talks & videos
- Functional World #1 ▶️ ZIO inception by Vladimir Pavkin (correct sound)
- Functional World #2 ▶️ Exploring ZIO Prelude The game-changer for type classes in Scala
- ZIO Prelude presented by Jorge Vasquez — Scala Developer at Scalac [ZIO World]
- ZIO WORLD — ZIO WEB by Piotr Golebiewski
- Jakub Czuchnowski, CTO at Scalac presents ZIO PULSAR [ZIO World]
- ZIO SQL presented by Scalac’s CTO — Jakub Czuchnowski [ZIO World]
The partnership with Ziverge
Scalac and Ziverge, the Company behind ZIO with John De Goes as its CEO, have been partners and friends for a long time. This partnership is about a joint vision of building advanced technology that simplifies and empowers developers.
The process of co-creating a ZIO Scala library article with experts
Our team came up with an idea to expand on the ZIO topic to provide a great reading experience for Scala enthusiasts, but more importantly to start a discussion.
This concept has sparked a surge of enthusiasm, and we have decided to raise this topic among Scala Developers from Scalac (who are into ZIO), and simply ask them if they would like to know other ZIO devs opinions and experiences.
It turned out that there are plenty of questions, but for our first article we chose 8 questions and asked 7 Zio experts and Scala developers what they think.
From here we would like to thank all the experts who shared their knowledge with us. Your word is essential in evangelizing Scala and ZIO. Thank you, for creating with us this truly functional and energetic Scala community.
Do you want to embrace the functional powers of ZIO?
We hope you enjoyed the article and invite you to contact us through chat or email at zio@scalac.io or simply by writing to Jan Nasiadka or Agata Nowak, on LinkedIn. We’re planning more publications like this in the future, and we would love to publish your insights!
We’re also always here If you need mentoring, training, or just want to talk ZIO (no strings attached!).