Spring to ZIO 101

How would one coming from a Spring background get their bearings fast with FP & ZIO?

The answer is below.

I onboard new team members coming from Java + Spring backgrounds to Scala + ZIO by starting with a 1-2 day training session where I present the main functional concepts they will work with. 1-2 days is enough to cover the basics and have someone at a level where they can begin to contribute to an existing codebase. 

Even though people are very receptive, understanding how that translates to a regular project is not always a straight line. Showing them how it is done on complex projects or ones where they are unfamiliar with the domain sometimes diverts focus from the main point.

One of the reasons a framework like Spring is highly successful is because it provides clear simple examples for what it has to offer.

So why not provide a simple example of a Scala + ZIO setup for a regular scenario most people are familiar with?

A regular blog post would give you a Pet CRUD. But my readers deserve the best, this will be an Employee CRUD. 🙂

Let’s make a CRUD for an Employee using Scala + ZIO and see how it looks like.

I will use the following DDD based directory structure that should be familiar enough to most.

  • com.adrianfilip.ziosample
    • domain <- all business goes here, the business’s external api is here
      • api
        • EmployeeApi    <- Could also be called EmployeeService but I prefer to use the term API
      • model
        • Employee
          • Employee     <- this is the entity model 
          • EmployeeRepository  <- this will contain the contract for the repository (and in this case also the accessor methods)
    • infrastructure  <- all non business goes here
      • environments
        • EmployeeRepositoryEnv  <- this will contain all EmployeeRepository implementations
      • persistence
        • EmployeeRepositoryInMemory  <- this is the implementation of EmployeeRepository that persists in memory
      • Controller  <- parallels its Spring counterpart
    • Application    <- main program

Let’s start with the model. The Employee will look like this:

Notice the use of the smart constructor to forbid creation of invalid state.

Next we have the EmployeeRepository.

Notice the use of ZIO[R, E, A] here. The short version description here is:

ZIO[R, E, A] describes a program where:
R – is the type of the environment needed to run the program (tldr: R = the dependency)
E – is the type of the failure the program can fail with
A – is the result of running the program successfully

This setup may look a bit verbose but it’s worth it.

Q: What happens here ZIO.accessM(_.get.save(employee)) for instance?
A: ZIO.accessM is used to access the provided environment. So you can read the above as: Give me the provided EmployeeRepository.Service and call its save() method.

Q: Where is EmployeeRepository provided and who provides it?
A: Any client that wants to use the save program ZIO[EmployeeRepository, PersistenceFailure,Employee] has to provide it when it uses it.

Now that we have this we can move on to the API. Considering my business logic will always be the same here and only the context (environment) may change I can use an object where I describe the business of each operation like this:

Notice here that:

  1.  EmployeeApi.create describes a program that in order to run it needs an EmployeeRepository.
  2. I only describe that I need an EmployeeRepository, I don’t actually provide one via any type of injection and one is not available in the object. How does that work? I’ll come back to this later.

Next we have the Controller. Because I wanted to keep things simple the user will interact with the app via the console. In the controller operations I implement the interaction with the user.

There are 2 things to notice here:

  1. Controller.create is a program that will need both a Console and an EmployeeRepository to  run unlike EmployeeApi.create which only needs an EmployeeRepository.
  2. When EmployeeApi.create is used there is no mention of any EmployeeRepository. That is because it will implicitly use the EmployeeRepository provided to  EmployeeApi.create. Pretty useful right.

How about running this whole thing?

First I create a program that looks like this to describe how the high level interactions with the user will go and it also acts as a dispatcher from input to each Controller operation:

You can notice here:

  1. how easy it is to create a CLI because of the compositionality provided by ZIO (this thing led me to create most of my utilitaries as CLI’s now, it’s just soooooo convenient for those utilitaries that don’t require a very complex UI where you need to add an http server and maybe also a SPA)
  2. ApplicationEnvironment in the R position

What is that ApplicationEnvironment? That is my alias for the required environments to run this app. (See picture below)

Up to this point I only described programs and how they compose.
In order to actually run them I will need a Console and an EmployeeRepository. Console is provided by zio and for EmployeeRepository I have a custom in memory implementation which I use to create the localApplicationEnvironment Layer by composing it with other environments (like console).
And how do I provide all this to my main program? Like in the picture below.

Notice here that:

  1. I can compose environments – see localApplicationEnvironment
  2. provideLayer is used to provide the environment to a program
  3. You can simulate spring profiles by selecting the environment you want based on the parameters you start your app with – here for example if the app is started with sbt “run local” the provided layer will be localApplicationEnvironment)

And with this we have a full Employee CRUD controlled by a CLI implemented only with Scala + ZIO.

Notice that:
– you can create fully composable software with ZIO
– you don’t need dependency injection

Hope this answers some of the questions regarding the transition to FP with ZIO.

The entire project is available at https://github.com/adrianfilip/zio-crud-sample, feel free to clone the repo, run the app and play with it.

You can find me https://twitter.com/realAdrianFilip and https://www.linkedin.com/in/adrianfilip/.

Extra mentions:

  • For more info about ZIO you can start with this Tour of ZIO from John De Goes
  • I may create a new post where I replace the CLI with some REST services. Either way check out this Wiem Zine http4s+zio post.

10 thoughts on “Spring to ZIO 101

    1. Hi Mike,

      If you are interested in the CRUD and DI part I think there are tons of samples online of java + spring CRUDs.

      But If you are interested in the entire app (crud + CLI) then I’m afraid the answer is no.

      You can have a version that will provide the main features for the end user but there will be tradeoffs in comparison to the ZIO version.

      Because idiomatic spring in java does not work with effects as values (while ZIO does) you will never be able to achieve the level of reuse and composability present in the ZIO version without using custom constructs and even then you will miss out on the out of the box support for concurrency, testability and resilience that come with ZIO. (ZIO also has a powerful answer for resource safety also but I am not mentioning it because it doesn’t really apply to the example in my article).

      In new articles I will expand on these aspects

      Like

      1. Hi, realadrianfilip!

        I just wanna say that if you want to really do the comparison between two things it would be nice to have both of them in your article/repo.

        > Because idiomatic spring in java does not work with effects as values (while ZIO does) you will never be able to achieve the level of reuse and composability present in the ZIO version without using custom constructs and even then you will miss out on the out of the box support for concurrency, testability and resilience that come with ZIO.

        Why spring should do that? What level of reusability is not achievable? Regarding testability and resilience. Do you wanna say that app written using Spring can’t be well tested or it is not resilient? And in general how can you compare Spring (I think you mean Spring MVC. web framework + DI lib) with ZIO (concurrent effects lib)?

        Like

      2. Hi Mike,

        > I just wanna say that if you want to really do the comparison between two things it would be nice to have both of them in your article/repo.

        I see your point but it’s based on a false premise.
        This article is about helping people coming from a Spring background quickly get their bearings when switching to ZIO not doing a comparison of Spring and ZIO. The contrast in some areas is only to provide a notion of familiarity.

        > Why spring should do that?
        I don’t think Spring should do anything different, they do things in a way that works for a lot of people and I’m glad it’s a useful tool. I used it successfully in the past, I even still have some projects running on it.

        > What level of reusability is not achievable?
        The level of reusability provided by the referential transparency that comes when using functional programming (in this case via FP via ZIO).
        I recommend this article. It goes more in depth on this: http://degoes.net/articles/easy-monads

        > Regarding testability and resilience. Do you wanna say that app written using Spring can’t be well tested or it is not resilient?
        I never said that, please check the context. The point I was making is you shouldn’t try to replicate ZIO in Spring if you want to work with descriptions of effects because you will miss out on ZIO features

        > And in general how can you compare Spring (I think you mean Spring MVC. web framework + DI lib) with ZIO (concurrent effects lib)?
        This depends on context.
        In my case I used both Spring and ZIO for backend development and I could reasonably compare them on how they perform at accomplishing that and the properties of the resulting code.
        I will try to make one of my next articles about this.

        Like

  1. > The level of reusability provided by the referential transparency that comes when using functional programming (in this case via FP via ZIO).
    I recommend this article. It goes more in depth on this: http://degoes.net/articles/easy-monads

    Why referential transparency can not be achieved in Java? Just split logic in pure functions and use them.
    And again all these questions come from that fact that you don’t show any implementation from the spring side.

    I just don’t like that nowadays ZIO fans do a lot of loud statements without proving them. This article is a good example.

    Like

    1. @Mike

      I choose not to read that last part as malicious so I will answer this time.

      > Why referential transparency can not be achieved in Java? Just split logic in pure functions and use them.

      Technically you can but Java is not FP idiomatic so the use will be limited.

      >And again all these questions come from that fact that you don’t show any implementation from the spring side.

      If you need proof that Java + Spring is not FP idiomatic so any attempt to replicate smth like ZIO in it will not look pretty you can check Kotlin Arrow. Kotlin is much more FP friendly than Java and it still does not provide the same FP experience as its Scala counterparts.
      For me it’s not worth discussing about how much FP you can do in Java with the current syntax and I will not engage on this topic further.

      > I just don’t like that nowadays ZIO fans do a lot of loud statements without proving them. This article is a good example.

      My statements about ZIO are proven in this repo https://github.com/adrianfilip/zio-crud-sample and you can find plenty more statements and proofs from other “fans” here https://zio.dev/docs/resources/resources.

      There is also an online weekly newspaper https://mailchi.mp/softwaremill/scala-times-issue-2608499 with related topics that might be helpful. (I just linked it because this article made it there. Just kidding, it’s really worth it to check it out.)

      Hope that clarifies things a bit more Mike,
      See you around!

      Like

  2. Thanks for this. I’m actually new to the Spring Boot space, so this gave me a context to understanding how SB developers think about making services. I forked your code (murraytodd @ GitHub) and updated it to the new cleaner ZIO 2.0 ZLayer module pattern.

    Like

  3. Hi, Thanks for such a great article, This is the only article I could find for someone from Springboot to ZIO. Keep Posting more.

    Like

Leave a comment