94

Happy Path: Kotlin + Actors + Kategory (proof of concept)

 6 years ago
source link: https://medium.com/@javipacheco/happy-path-kotlin-actors-kategory-proof-of-concept-322e9099d2ea
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Happy Path: Kotlin + Actors + Kategory (proof of concept)

1*kF_bpeNe0THMssFEa2enYA.jpeg

Photo by Jan Phoenix on Unsplash

For a while, I’ve been away from Android programming, and even more so from Java, and I was too lazy to be back to into the same problems (listeners, nulls, libraries, etc.) in my “return to Android”. I’ve been close to the Backend for the last few years, especially doing Scala and Raúl Raja :-p, it has made me think about solving problems in a different way. I’m not a Functional Programming purist or anything, just more pragmatic, I don’t code because I like to make the best code in the world (although I would like to try to do it), I code because I like to build things.

But sometimes unexpected things happen.

In the last month, a friend (maybe an enemy, I won’t say his name: -p) told me to help him with a project that he had to finish, and it was made in Java. My eyes were bleeding with all those listeners and !=null. Besides everything with the MVP pattern: Presenters, Interactors, Dagger, Views and all its things… why can’t we call all of them the same way! What’s the problem if something makes a call to an API, store something in your database or change your view?… how nice it would be if everything was called the same.

But let’s start from the beginning. Kotlin is the coolest language now! My friend

told me that but I didn’t want to believe him: -p. Thanks to it, we can solve part of the problem of my proof of concept, but I need something else… Monads, Options, Eithers… I need Data Types from the functional point of view. Then, Spanish guys interested in Functional Programming made Kategory… and it all started to make sense.

Prerequisites

I’ve created a small project called Rekkit that can be found on GitHub. It’s a simple proof of concept WIP, a Reddit message viewer. The project has got two packs:

  1. A package called akme. Yes… as the Coyote and Roadrunner but with a K on it. This would be a “little library”, with the types of data, exceptions, extensions, etc.
  2. A package called rekkit with the application

The Concept

We are not going to explain what’s a Monad, for that there are already others who do it perfectly, for now it will be enough to know that it is something that implements map() and flatMap() and as they say in Wikipedia “a monad defines what it means to chain operations together”. Let’s take an example of a very simple application in Android. We want to show a list of news coming from a web server. Let’s see what the steps would be:

1*bePqAw0CQ6nlCqxFmfeQVw.jpeg

Simple. Several important things here:

  1. This is our happy path. We are not taking errors into account… or so it seems.
  2. We are mixing UI actions (loading and drawing on screen) with API calls (download news)

In Java or Kotlin, we would be thinking about showing loading and then call the API with a CallBack, which will tell me whether there was an error or everything went well with the news list… and then I show the news on screen. Maybe it’s not done that way anymore, but something like that could be thought of by a lot of people.

Our idea is that everything is the same, and even if we only think of the happy path, we can also have the possibility of recovering from possible errors. For this, we’ll use Kategory’s Either. In the documentation, it’s very well explained on the documentation. What we are going to use is the section “Either with ADT Style”, which we are going to try to explain now.

An Either is a data type that has 2 parts:

  1. The right side: it’s the type of data we look for, for example in the API call can be the news list
  2. The left side: it’s our exception. If we’ve got a failure, you will return the left side, in our case the ADT of exceptions

You can only get one side or the other, but not both at the same time.

Note: Algebraic Data Types (ADT) is a type which is represented by several other subtypes. You have more information here. In our case, the Exceptions of our application

In Imperative Programming, we were used to throw exceptions, but on Functional Programming we would return something, so the Either is perfect for us, it returns the right side (the thing went well) or the left side (the thing went wrong). If our data type is:

Either<Throwable, List<News>>

Our call should return the news list if everything went well or the error if it went badly. We have no surprises of exceptions that we have not checked in our code since it is part of the returned type.

Either.Right(List(news1, news2))
Either.Left(ApiException())

In this project file, you can see the data types for our proof of concept. As we have said our left side will be an ADT with all of Exceptions that we define in Kotlin through sealed classes. The sealed class of our ADT is called AkmeException and we will also create a data type called Service:

IMPORTANT! Everything for us will be a Service, or we will have to transform it into a Service. By doing that, we will be able to compose all our services in our happy path, as we will see later on.

Creating our Services

Let’s see our service for API calls. In a moment of lucidity, I called it ApiService: -p and you can see it here.

I’m using retrofit, by all known (here a post of how I integrated it into Kotlin), and our ApiService has a getNews method that returns

Service<ListKW<States.NewsItemState>>

As we have said, all our services return a Service, and the positive case is our news list.

Note: ListKW is a type of Kategory that represents a list we can use in the “monadic way”

But if retrofit calls return a Call? How can we turn it into a Service? To do that, we use Kotlin extension functions in order to add the toService () method to Call object.

And we can do things like that now:

fun getNews() = redditApi.getTop().toService()

What about the UI Services? Well, Android can have problems around that: Contexts, run in the UI thread, resources, etc.
The best way is to create an interface that you should be implemented in the Activity or Fragment, as you can see in the NewsUiService.

The idea is to send these services to an entity in order to be used. For example, APIService and NewUiService would have functions that return Service and are able to be composed to make more complex tasks like: show loading, download news and display that news on the screen.

Composing our Services

Do you know what a for comprehension is? Sure if you come from Scala like me, but maybe not, if you come from other non-functional languages… and it’s a shame because it’s wonderful.

Remember that before we said that a Monad implements map() and flatMap(), and now we are going to see why it’s so important. Our Service is an “Either Monad” and we can easily compose it with others Service thank to flatMap(). But, what’s that flatMap()? Well, let the experts explain them. We only need to know that we can easily compose it in series in a sequence of steps.

And then, what is for comprehension? As the implementation of flatMap() when you compose several services can be a little complex to read, this is just syntactic sugar, something that makes it easier to read those nested calls.

Kotlin doesn’t have it, but Kategory does. If you want to learn more about Monad Comprehension in Kategory from an expert, look at this post by my friend Jorge Castillo who explains Monad Comprehension in Kategory.

And we, let’s see it! We can combine our services as we saw in our picture earlier.

Do you remember? On line 2 we show loading, on line 3 we call API and assign the list of news to the variable “news”, and finally, we call the showNews service with that news on line 4.

Cool!. No listeners, no nulls, no mess… just our happy path.

Well, how do we control our exceptions? Easy. If you look at the “yields” statement, it contains the exit of our happy path, but if it fails we come out with the exception. FlatMap for Either is a right-biased, which means that the value on the right is assumed as the default case of the operation, so if one of them comes out on the left side, the following cases are not computed. Something like the following picture. Remember that I’m a programmer, not a designer :-)

1*CJ04YUEcEc7ZyXq6BMV6yQ.png

For example, if everything goes well we would receive a Right(Unit) because it is what we return in the yields, but if the news download fails it will return a Left (ApiException()) or if the Ui the ProgressBar is null should return a Left (UiException()).

Easy, isn’t it? But there’s still something wrong here. Ups, ok!!

All of these calls are synchronous and API calls should be asynchronous. What do we do?

Although Kategory has an IO Monad for resolving asynchrony, and we could use an EitherT (it’s not necessary to explain now), I decided to use the Actor pattern for asynchrony and so I can also maintain the state of my application within the Actors.

Actors: State and asynchrony

My first thought was to use Akka. I even implemented a version using it. I have created a Tag on GitHub with a version using Akka Actors. But in a conversation with

talking about the proof of concept, he told me that Kotlin also had Actors, I read about that and it had all my needs and didn’t need to use a big library as Akka to my project.

What are the Actors? As a first idea, they are small entities which you can send messages to and contain a state. This state can be mutable. For example, we can add new or old news to our Reddit news list. It’s the only one mutable feature in our application (well, the Adapter also has a mutable variable).

Let’s see how an Actor looks like:

I’ve simplified a couple of things to make it more readable, but this is the Actor to load the Reddit news. First, we see that we have created a class called NewsActor that will contain all the actors (I’ve put only one but in the original class there are two). Several things we should notice:

  1. Parameters: We pass the Services as parameters. Remember that our services contain the methods that return Service and can be combined with each other. Here we have the service of Ui and Api
  2. Status: On line 4 we see the status of our application. It is mutable and when the Actor starts the list is empty
  3. Commands: I have called Commands the messages that can be sent to an Actor to do actions. It’s a sealed class again, and you can see here the list of actions. For example, actions to display a message, show news, go to a new screen, etc.
  4. Notifications: I have called Notifications to actions that are triggered after an error occurs. The control of these notifications are in another actor, in this case it is called notificationActor

Once our Actor is created, we can send messages using the send() method and even communicate with other actors (for example, I use it that when I have an exception sending a notification)

This picture shows how it is done:

1*KCzaAx53JQW7URPxPg_FtA.png

The application sends a Command to the news actor, if all goes well, everyone is happy. If it goes wrong, send a Notification to the notification actor, who know how to solve the problem and all happy.

It is important to explain the two patterns of the Actors:

  1. Tell Pattern: this is the one we are using here and it is a Fire&Forget. We just launch the command and forget about it, the actors will solve the problem between them.
  2. Ask Pattern: we launch the event and wait. We do not use it in this project but it can be used to obtain the inner state of the Actor. You have an example on Kotlin documentation

Finally, let’s see how to call the Actor. Here I leave you a part of the NewsFragment code which is the Fragment that loads the news. As we said, we can communicate with an Actor using the send() method or “command” in our case. I have added the sendBlocking() method using Kotlin’s extension functions since it is necessary to run within an asynchronous context with runBlocking(). I don’t know if it’s all right, but I’ve done it to improve code readability.

In line 5 we see how we create NewsActors, which contains the actors that we are going to use in our Fragment with the services as parameters (note how the service of Ui NewsUiService is the Fragment itself).

Finally, see how on line 10 we call the actor and send him our NewsGetItemsCommand command with the limit of items we want to show.

Remember… Fire & Forget… forget everything, actors know what they have to do… and always in an asynchronous context.

Conclusion

Many developers who switch to Kotlin are pretty much working in the same way they did for Java, the same patterns and libraries. Yes, with a lot of changes, Kotlin is cool, but many still work the same way.

This proof of concept is part of what we worked on 9Cards when I was working 47 with Fede, Paco, Domin and Raul making an application with Scala on Android. But we didn’t work with Actors back then.

Honestly I feel more comfortable working like this, maybe at first it’s hard, but I want to continue investigating on this way.

In the future, I’d like to investigate about persistence. One thing I found very interesting about working with Actors, specifically Akka, was Akka-Persistence. It’s something that we worked a lot in Backend with my friends Rafa Paradela, Fran Pérez, Juan and Javi Siloniz… do you remember Protocol Buffer? We had a great time: -p…. What it does, in essence, is that when we start an Actor, he recovers the previous state before closing it. Imagine if you have all the news you’ve read before in the Actor’s state when you start it. Cool! It’s very interesting to keep a cache or work offline.

I would certainly like to investigate it and try to implement it… but for that there is still time.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK