As you may already know, ZIO is designed around three type parameters:
ZIO[-R, +E, +A]
You may also remember that a nice mental model of the ZIO data type is the following:
R => Either[E, A]
This means a ZIO effect needs an environment of type R to run, meaning we need to fulfill this requirement in order to make the effect runnable. More concretely, this R type represents a dependency on a module or several modules that are needed for running the effect. Therefore, let’s now discuss how modules are defined in ZIO.
As mentioned in the ZIO documentation page: “A service is a group of functions that deals with only one concern. Keeping the scope of each service limited to a single responsibility improves our ability to understand code, in that we need to focus only on one topic at a time without juggling too many concepts together in our head”.
The idea is that ZIO allows us to define modules and use them to create different application layers that rely on each other. This means each layer depends on the layers immediately below it, although it doesn’t know anything about their implementation details. This is a really powerful concept because it improves composability and testability (because you can easily change each of the module’s implementations without affecting other layers).
Now, if you are thinking about how to define these modules, ZIO provides us with a nice recipe to follow when defining a new module. This recipe should be familiar to object-oriented programmers:
Don’t worry if this all seems too abstract at the moment because we are going to be applying this recipe to implement the Tic-Tac-Toe application later. The only important thing for now is to get to know ZLayer, a very important data type mentioned in this recipe, and which is related to another very important data type: Has. So let’s discuss those now.
As mentioned in the ZIO documentation page:
The ZLayer data type is an immutable value that contains a description for building an environment of type ROut, starting from a value RIn, possibly producing an error E during creation:
ZLayer[-RIn, +E, +ROut <: Has[_]]
Again, don’t panic if this doesn’t make too much sense for you at the moment, because we are going to be applying both the horizontal and vertical compositions when we implement the Tic-Tac-Toe application and everything will become clearer. As a side note, there are other additional operators for combining layers, which we are going to be talking about later.
Finally, it’s worth mentioning that ZIO provides some type aliases for the ZLayer data type which are very useful when representing some common use cases. The good news is that the logic for defining these type aliases is practically the same as that applied for defining the ZIO type aliases (for reference, you can take a look at the Quick Introduction to ZIO section of this article where I talk about concurrency with ZIO STM). Here’s the complete list:
Now, if you are wondering how to create ZLayers, stay tuned because we are going to be seeing how easy that is to do in the next section.