Lean async code with Kotlin´s coroutines
Sabag, Ronen
Software Engineer, love programming, passion to produce good code, currently doing Android development and love to do it with Kotlin and Clean Architecture.
 So hey all my name is Ronan. I'm working in company which called get it's like international player in the mobility area and Today we're going to talk about a synchronous code with Kotlin coroutines so first of all we're going to Discuss and to put all of us on the same page about what they meaning with a sync code After that we're going to discuss a bit what is coroutines we're going to see coroutines in practice and then we're going to summit with that we've How to why we need to use coroutines? Alright, so a sync code basically a sync code it's meaning Not surprising you're going to run the code not in sequence way so basically most of the time you're going to have like some callback and You're going to do some job and after that you're going to call to this callback and I don't believe it varies like a Real up today that doesn't use any a sync code So I want to emphasize the different between observation and synchronization So let's save it. We have like this architecture that for example taking a Repos from GitHub and displayed on the UI So the UI will call to interact or we give it some callback Because we can do for example network on the main thread. So need to do it in another thread the interact or first wheel Enqueue the request with the network client Let's say that we're using retrofit so it's going to incur it and After that you're going to go to the repository and put the data there. So this was like a synchronization We use oh, it's going to call first the interact or to give it back the The data that it took from the network and then the interact are going to put it in the repository So it was like a synchronization between the work with first of all I need to get Actually the data from the network and only after that I can put it in the repository So after that the interact or will go to the UI and the UI finally can start to observe the data from From the repository so we have like two models. We have the observation which It's going to be pushed to the UI every time that the change is going to be in the repository and Very in the beginning of that we have like the synchronization I need to do this first and only then I can do the other job that they need to do All right, so what is coroutines? Coroutines is basically just a piece of code that can be suspended and resume in Kotlin each coroutine is going to be compiled by the it's going to be changed by the compiler to a state machine and each suspendable place it's a separate a suspendable function is going to be Like a state in the state machine It's very old concept causing didn't invent it. It's basically Start at some times in the 70s. There is like Implementation of that we've see C++ scheme and not even with some more more than languages like C sharp and go long What really nice about the coroutines that the compiler in at least in the case of a Cotton the compiler is going to hide from me all the complexity and the code inside the coroutines can be sequentially and it's really nice Kotlin support coroutines starting from One point one point one. It's still an experimental mode, but it's not because they just Thinking whether or not to kill it. It's because they want to polish the API's before we're going to declare it as release So it's okay to use it In Kotlin there is like suspendable function which mark with suspend function and only core only coroutines can run the suspend functions so Like I told you before there is like suspend function each one of them actually is going to be translated to some state in the state machine and By that we can get gain the nice readability with coroutines And most of the coroutines that written by jetbrain. It's coming from this extension library It's called a Kotlin Kotlin X coroutines and it's really open source and everybody can Can contribute to that they do accept external pull request So let's see coroutines in practice so like I told you I working in a company which called get in the mobility area and and among other services, but we have we have like pre-prereouts Which was pre-defined like fixed routes and anyone can various like cars that going along the along the line along the line And everybody can just pop in and pop out from the from the car and we have also integration with application Which called city mapper? With city matter your city mapper provide us the lat and the long of like the GPS coordination of The journey that the user want to do and we need to do a lot of things We need to calculate what is the fastest walking path to the for the to the line and from the line And where we need to go and when you need to go off and There is a lot of things that we want to do and we want it's going to be smooth So for that we need to gain some performance in addition We have like there is like the green dots there, but it's the walking path and we're going to change to convert the GPS coordinate to the to actual address like a string and a lot of things that we want to do and we want to do it as fast as we can So for now we're going to deep dive just for the conversion of the GPS location the lat and the long to string so for in this case we have like a Function which call and the deep link it's getting the request everything that he needs reside inside the request and Everything that's going to go back to whatever call it. It's going to be in the response so first of all we want to take the start lat long and to Convert it like a string and the same thing with the Atlanta lat long and by that we can just put in the UI the addresses instead just to give and Now a location So this is how we're going to do it in synchronous in synchronous word way We're going to do the first one and after that we're going to do the second one But I can actually do it in parallel. So in core teams I can do it like this in parallel I Going to first explain what is the launch core teams or lunch? It's called. It's a function. It's correct in function Which gets a lambda? Everything that inside the lambda is going to run immediately the launch return a job structure that's called a job that I can do several things with him and And eventually what is going to happen here in the code is going to run the first one and the second one It's going to run in parallel Now the second thing that they're going to show you here. It's the run blocking when I want to wait for something to happen before I'm going to continue with the With the execution I'm going to put it inside block of run blocking The Join that we're doing inside the run blocking its suspend operation. This is actually suspend function and this is how the The compiler know how to turn you know how to translate it and because of that you can just put it like that We don't need to give some callbacks for that So it's really nice. It's working, but I Want to make it a bit more readable So I can just wrap the launch Coroutines with my function which I call it in parallel because for me it's mean a lot and It's going to get just a task Instead of doing the run blocking inside the code that going to introduce like extension function for list of jobs Which will do that actually the same thing. It's going to take everything inside the list and join So it's going to wait until all the jobs inside this list will end And finally I want also this task will be bounded to some life cycle And I can do it very easily by introducing something that I call it job counselor, which is also life cycle observer so When I when I just Initialize this this class this job counselor I can register a career register it to some life cycle Owner so it will be aware to the life cycle On destroy those of these lifelife this life cycle I will just go go over each one of the Jobs in the list and I'm going to cancel it by that it's going to be bounded to life cycle All right, so with these abstractions my code look a bit nicer for least for me Now I kind I it's it's written I doing two things in parallel and Then I go in to put all of them with the job counselor It's so it automatically will be closed when the life cycle will be destroyed and Finally, I'm going to wait for all All right, so it's really nice, but now I have like a different problem. I want to make Two tasks to run in parallel, but just take the first one of them for example Let's say that we have two providers that know how to reverse geocode from a lot long to some string One of them is Google and the other one is my best friend Startup and I want to help him so we're going to use both of them So now because instead of using the lunch coroutine, we're going to use a sink a sink. It's doesn't like unlike Lunch it doesn't start the execution right away It's going to wait. I turn we're going to do a wait or on a wait in this case And it's returning defer which defer it's something that extend the job, but it can also bring me back like value So I going to have these two sink blocks and then I want to wait for the first one So first of all we're going to look at on the select select. It's another coroutines that know to select the first first one of these jobs that will end first so We have like the first provider that we're going to await on it on the second provider and When I going to call to on await, it's literally going to start the work in their sink And with that the first one that will finish probably of course not Google. It's going to be my best friend the startup We're going to get a result and this is going to be actually the return value and Because we want to wait for the first one we wrap all of that with one blocking. So once again, it's walking It's really nice, but I want to make it more readable So what I can do like before I'm going to provide my own abstractions I'm going to wrap the sink call with this call that's called with this function. It's called fetch address with provider All this select code it's going to be wrapped in extension function this time instead of jobs of defer jobs and They're going to call it first a wait for first And now I can use my abstraction in the code look much more nicer I have like fetch the first one first fetch the second one put all of them in the job canceler because I still want to be bound to the life cycle and Then I'm going just to wait for the first one So it's much more nicer much more elegant than before so Until now we just saw examples of Synchronization between two jobs that we want to wait for the first or do both of them in parallel Let's see how can we observe things with coroutines? So in coroutines there is this notion of channel channel. It's like It's like a message queue that's which can connect between it's like network between two coroutines and Basically, China's have some capacity So let's save it the channel have capacity of two if I want to write something to the channel and It's fully fully occupied. So I'm going to be suspend until Somebody will pull something from this message queue and if I want to receive something but it's empty So once again going to be suspended and wait until Somebody will write to the channel in this case We're going to use special channel like it's a broadcast broadcast channel, but it's not just a broadcast channel His capacity is confluent what it's basically mean that we're going to have a lot of subscribers which can or consumers which can start to consume this channel Everybody of them going to get when you're going to first to observe the chains you're going to get the latest value and When I update a new value all of them get the same the same value so we have this broadcast channel and I just call it like a walking in for stream. I going to take from the network the walking path and then I want to put the initial walking path so the y can start observing things and Like I told you before send its suspend operation. So I must wrap it with coroutines and And after that I going to call some function which will do the calculation with the location and update the The walking path every time that something has been changed and we're going to return it as response In the UI side what we need to do we need to get this broadcast channel open subscription This is the way that we open like a new a new subscriber. That's going to To be notified about the changes and Then we starting to consume it now are using here a while because I don't want to get only once the value I want it's going to be of there all the time. So we're going to use this while the channel is not closed and I get something if it's not now I'm going to push it to the channel and then everybody that's listening to this channel Can take it and do it it whatever you want But it's very complex so I going to introduce additional abstraction of my own So this time I going to start with the data stream So that a stream is just something that gets a subscription subscription from type of receive channel and And I going to introduce their like two methods one of them I call it notify on change which basically hide all the boilerplate that I had to do in order to consume values from the to consume values from the From this channel and I going to have for that close because if I don't want to observe any change anymore I can just close it With that I can just Use another abstraction which called data store and that is so right for me the Brought us the broadcast channel And the varies like a set current value which do everything that we need to do with the lunch and shutdown and In the bottom we have like the get data stream which remain return for me the data stream from the previous slide and With that my code is look On the end of deep link it's looked it's look a bit nicer because I don't have to put the lunch there and It's nice, but when I'm consuming This events it's look much much more elegant now All I need to do is just to take from the response the walking path of data store Get the data stream and be notified on change and do something with this change All right, so why coroutines and Especially why coroutines when we have other libraries like Rx Java So this example, it's not mine. I took it from some jet brain slides But it's really pin the point that I want to to make clear like we have your Example of two codes that we need to write both of them doing the same jobs. We have like user that we're going to to get some Creditionals and do login after we're going to do the login we're going to get like a user ID and with the user ID we're going To load some user data and we're going to show it so in the Rx Like in the left side We're going to declare the login as a single and the load user data as a single and Spoiler every time that you're going to use Single you need to think maybe it's not the right tool for what we need to do because In this case all we need to do is just to synchronize between things so the code is look like that We have the login with conditional flat map to Load the user data we on on success. We're going to show the data. We need to subscribe on that on the right on the right side It's not just the right side. It's actually the right side So everything is going to be Sequentially because we're going Like I described it to you are just going to do the login Get the user data and show it and it's much more readable at least for me Besides that why to use coroutines so The code inside the coroutines get can be expressed sequentially I Can build my own abstraction. It's very easy to do it. So the code will be very Readable for me and my team and everybody every new guy that will come to the team It will be very easy to him to jump in and start coding there is a lot of Integration with other major frameworks that's coming out of the box from Jetbrain like we've are X1 and are X2 and Java 8 streams and it's very easy to write additional one if you want and we have some talks about multi-platform and Jetbrain indeed working on on porting the coroutines to other platforms so there is right now I think already Implementation for JavaScript and they're working also on native so in world of multi-platform it could be very nice way to do a sync code in In in the common libraries that we're going to have and with that I want to thank you if you have any questions. So I'm going to be around and Thanks a lot
 So hey all my name is Ronan. I'm working in company which called get it's like international player in the mobility area and  Today we're going to talk about a synchronous code with Kotlin coroutines  so first of all we're going to  Discuss and to put all of us on the same page about what they meaning with a sync code  After that we're going to discuss a bit what is coroutines we're going to see coroutines in practice and then we're going to summit with that we've  How to why we need to use coroutines? Alright, so a sync code  basically a sync code it's meaning  Not surprising you're going to run the code not in sequence way  so  basically most of the time you're going to have like some callback and  You're going to do some job and after that you're going to call to this callback and  I don't believe it varies like a  Real up today that doesn't use any a sync code  So I want to emphasize the different between observation and synchronization  So let's save it. We have like this  architecture that for example taking a  Repos from GitHub and displayed on the UI  So the UI will call to interact or we give it some callback  Because we can do for example network on the main thread. So need to do it in another thread the interact or first wheel  Enqueue the request with the network  client  Let's say that we're using retrofit so it's going to incur it and  After that you're going to go to the repository and put the data there. So this was like a synchronization  We use oh, it's going to call first the interact or to give it back the  The data that it took from the network and then the interact are going to put it in the repository  So it was like a synchronization between the work with first of all I need to get  Actually the data from the network and only after that I can put it in the repository  So after that the interact or will go to the UI and the UI finally can start to observe the data from  From the repository so we have like two models. We have the observation which  It's going to be pushed to the UI every time that the change is going to be in the repository and  Very in the beginning of that we have like the synchronization  I need to do this first and only then I can do the other job that they need to do  All right, so what is coroutines?  Coroutines is basically just a piece of code that can be suspended and resume  in  Kotlin each coroutine is going to be compiled by the it's going to be changed by the compiler to a state machine and each  suspendable  place it's a separate a suspendable function is going to be  Like a state in the state machine  It's very old concept causing didn't invent it. It's basically  Start at some times in the 70s. There is like  Implementation of that we've see C++ scheme and not even with some more more than languages like C sharp and  go long  What really nice about the coroutines that the compiler in at least in the case of  a  Cotton the compiler is going to hide from me all the complexity and the code inside the coroutines can be sequentially and it's really nice  Kotlin support coroutines starting from  One point one point one. It's still an experimental mode, but it's not because they just  Thinking whether or not to kill it. It's because they want to polish the API's before we're going to declare it as release  So it's okay to use it  In Kotlin there is like suspendable function which mark with suspend function and only core only coroutines can run the suspend  functions so  Like I told you before there is like suspend function each one of them actually is going to be translated to some state in the state machine and  By that we can get gain the nice readability with coroutines  And most of the coroutines that written by jetbrain. It's coming from this extension library  It's called a Kotlin Kotlin X coroutines and it's really open source and everybody can  Can contribute to that they do accept external pull request  So let's see coroutines in practice  so like I told you I working in a  company which called get in the mobility area and  and among other services, but we have we have like  pre-prereouts  Which was pre-defined like fixed routes and anyone can various like cars that going along the along the line along the line  And everybody can just pop in and pop out from the from the car and we have also integration with application  Which called city mapper?  With city matter your city mapper provide us the lat and the long of like the GPS coordination of  The journey that the user want to do and we need to do a lot of things  We need to calculate what is the fastest walking path to the for the to the line and from the line  And where we need to go and when you need to go off and  There is a lot of things that we want to do and we want it's going to be smooth  So for that we need to gain some performance in addition  We have like there is like the green dots there, but it's the walking path and we're going to change to convert the  GPS coordinate to the  to actual address like a string and  a lot of things that we want to do and we want to do it as fast as we can  So for now we're going to deep dive just for the conversion of the GPS location the lat and the long to  string so for in this case we have like a  Function which call and the deep link it's getting the request everything that he needs reside inside the request and  Everything that's going to go back to whatever call it. It's going to be in the response  so  first of all we want to take the start lat long and to  Convert it like a string and the same thing with the Atlanta lat long and by that we can just put in the UI  the addresses instead just to give and  Now a location  So this is how we're going to do it in synchronous in synchronous word way  We're going to do the first one and after that we're going to do the second one  But I can actually do it in parallel. So in core teams I can do it like this in parallel I  Going to first explain what is the launch core teams or lunch? It's called. It's a function. It's correct in function  Which gets a lambda?  Everything that inside the lambda is going to run immediately  the launch  return a job structure that's called a job that I can do several things with him and  And eventually what is going to happen here in the code is going to run the first one and the second one  It's going to run in parallel  Now the second thing that they're going to show you here. It's the run blocking  when I want to wait for something to happen before I'm going to continue with the  With the execution I'm going to put it inside block of run blocking  The  Join that we're doing inside the run blocking its suspend operation. This is actually suspend function and  this is how the  The compiler know how to turn you know how to translate it and because of that you can just put it like that  We don't need to give some callbacks for that  So it's really nice. It's working, but I  Want to make it a bit more readable  So I can just wrap the launch  Coroutines with my function which I call it in parallel because for me it's mean a lot and  It's going to get just a task  Instead of doing the run blocking inside the code that going to introduce like extension function for list of jobs  Which will do that actually the same thing. It's going to take everything inside the list and join  So it's going to wait until all the jobs inside this list will end  And finally I want also this task will be bounded to some life cycle  And I can do it very easily by introducing something that I call it job counselor, which is also life cycle observer  so  When I when I just  Initialize this this class this job counselor I can register a career register it to some life cycle  Owner so it will be aware to the life cycle  On destroy those of these lifelife this life cycle  I will just go go over each one of the  Jobs in the list and I'm going to cancel it by that it's going to be bounded to life cycle  All right, so with these abstractions my code look a bit nicer for least for me  Now I kind I it's it's written I doing two things in parallel and  Then I go in to put all of them with the job counselor  It's so it automatically will be closed when the life cycle will be  destroyed and  Finally, I'm going to wait for all  All right, so it's really nice, but now I have like a different problem. I want to make  Two tasks to run in parallel, but just take the first one of them for example  Let's say that we have two providers that know how to reverse geocode from a lot long to some string  One of them is Google and the other one is my best friend  Startup and I want to help him so we're going to use both of them  So now because instead of using the lunch coroutine, we're going to use a sink a sink. It's  doesn't like  unlike  Lunch it doesn't start the execution right away  It's going to wait. I turn we're going to do a wait or on a wait in this case  And it's returning defer which defer it's something that extend the job, but it can also bring me back like value  So I going to have these two sink blocks and then I want to wait for the first one  So first of all we're going to look at on the select select. It's another coroutines that know to select the first  first one of these jobs that will end first so  We have like the first provider that we're going to await on it on the second provider  and  When I going to call to on await, it's literally going to start the work in their sink  And with that the first one that will finish probably of course not Google. It's going to be my best friend the startup  We're going to get a result and this is going to be actually the return value and  Because we want to wait for the first one we wrap all of that with one blocking. So once again, it's walking  It's really nice, but I want to make it more readable  So what I can do like before I'm going to provide my own abstractions  I'm going to wrap the sink call with this call that's called with this function. It's called fetch address with provider  All this select code it's going to be wrapped in  extension function this time instead of jobs of defer jobs and  They're going to call it first a wait for first  And now I can use my abstraction in the code look much more nicer  I have like fetch the first one first fetch the second one put all of them in the job  canceler because I still want to be bound to the life cycle and  Then I'm going just to wait for the first one  So it's much more nicer much more elegant than before  so  Until now we just saw examples of  Synchronization between two jobs that we want to wait for the first or do both of them in parallel  Let's see how can we observe things with coroutines?  So in coroutines there is this notion of channel channel. It's like  It's like a message queue that's which can connect between it's like network between two coroutines and  Basically, China's have some capacity  So let's save it the channel have capacity of two if I want to write something to the channel and  It's fully fully occupied. So I'm going to be suspend until  Somebody will pull something from this message queue and if I want to receive something but it's empty  So once again going to be suspended and wait until  Somebody will write to the channel in this case  We're going to use special channel like it's a broadcast broadcast channel, but it's not just a broadcast channel  His capacity is confluent what it's basically mean that we're going to have a lot of  subscribers which can or consumers which can start to consume this channel  Everybody of them going to get when you're going to first to observe the chains you're going to get the latest value and  When I update a new value all of them get the same the same value  so we have this broadcast channel and  I just call it like a walking in for stream. I going to take from the network  the walking path and then I want to  put the initial walking path so the y can start observing things and  Like I told you before send its suspend operation. So I must wrap it with coroutines  and  And after that I going to call some function which will do the calculation with the location and update the  The walking path every time that something has been changed and we're going to return it as response  In the UI side what we need to do we need to get this broadcast channel open subscription  This is the way that we open like a new a new subscriber. That's going to  To be notified about the changes and  Then we starting to consume it now are using here a while because I don't want to get only once the value  I want it's going to be of there all the time. So we're going to use this while the channel is not closed and  I get something if it's not now  I'm going to push it to the channel and then everybody that's listening to this channel  Can take it and do it it whatever you want  But it's very complex so I going to introduce additional abstraction of my own  So this time I going to start with the data stream  So that a stream is just something that gets a subscription  subscription from type of receive channel and  And I going to introduce their like two methods one of them  I call it notify on change which basically hide all the boilerplate that I had to do in order to consume values from the  to consume values from the  From this channel and I going to have for that close because if I don't want to observe any change anymore  I can just close it  With that I can just  Use another abstraction which called data store and that is so right for me the  Brought us the broadcast channel  And the varies like a set current value which do everything that we need to do with the lunch and shutdown and  In the bottom we have like the get data stream which remain return for me the data stream from the previous slide and  With that my code is look  On the end of deep link it's looked it's look a bit nicer because I don't have to put the lunch there and  It's nice, but when I'm consuming  This events it's look much much more elegant now  All I need to do is just to take from the response the walking path of data store  Get the data stream and be notified on change and do something with this change  All right, so why coroutines and  Especially why coroutines when we have other libraries like  Rx Java  So this example, it's not mine. I took it from some jet brain slides  But it's really pin the point that I want to to make clear like we have your  Example of two codes that we need to write both of them doing the same jobs. We have like user that we're going to to get some  Creditionals and do login after we're going to do the login we're going to get like a user ID and with the user ID we're going  To load some user data and we're going to show it  so in the Rx  Like in the left side  We're going to declare the login as a single and the load user data as a single and  Spoiler every time that you're going to use  Single you need to think maybe it's not the right tool for what we need to do because  In this case all we need to do is just to synchronize between things so the code is look like that  We have the login with conditional flat map to  Load the user data we on on success. We're going to show the data. We need to subscribe on that on the right on the right side  It's not just the right side. It's actually the right side  So everything is going to be  Sequentially because we're going  Like I described it to you are just going to do the login  Get the user data and show it and it's much more readable at least for me  Besides that why to use coroutines so  The code inside the coroutines get can be expressed sequentially I  Can build my own abstraction. It's very easy to do it. So the code will be very  Readable for me and my team and everybody every new guy that will come to the team  It will be very easy to him to jump in and start coding  there is a lot of  Integration with other major frameworks that's coming out of the box from Jetbrain like we've are X1 and are X2 and  Java 8 streams and it's very easy to write additional one if you want  and  we have some talks about multi-platform and  Jetbrain indeed working on on porting the coroutines to other platforms so there is right now I think already  Implementation for JavaScript and they're working also on native so  in world of multi-platform it could be very nice way to do a sync code in  In in the common libraries that we're going to have and with that  I want to thank you if you have any questions. So I'm going to be around and  Thanks a lot
_DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_0_215.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_216_851.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_852_3791.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_3792_3839.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_3840_7067.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_7068_7139.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_7140_7187.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_7188_7427.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_7428_7475.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_7476_7715.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_7716_7775.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_7776_8003.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_8004_8063.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_8064_8291.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_8292_8351.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_8352_8579.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_8580_8639.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_8640_8867.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_8868_8927.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_8928_9083.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_9084_12275.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_12276_14903.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_14904_17687.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_17688_18395.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_18396_19211.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_19212_24755.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_24756_25451.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_25452_25559.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_25560_28055.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_28056_29879.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_29880_30083.png _DCBerlin18_111_Sabag_Lean_async_code_with_Kotlin__OWWsJeBE4hk_30084_30092.png
So hey all my name is Ronan. I'm working in company which called get it's like international player in the mobility area and Today we're going to talk about a synchronous code with Kotlin coroutines so first of all we're going to Discuss and to put all of us on the same page about what they meaning with a sync code After that we're going to discuss a bit what is coroutines we're going to see coroutines in practice and then we're going to summit with that we've How to why we need to use coroutines? Alright, so a sync code basically a sync code it's meaning Not surprising you're going to run the code not in sequence way so basically most of the time you're going to have like some callback and You're going to do some job and after that you're going to call to this callback and I don't believe it varies like a Real up today that doesn't use any a sync code So I want to emphasize the different between observation and synchronization So let's save it. We have like this architecture that for example taking a Repos from GitHub and displayed on the UI So the UI will call to interact or we give it some callback Because we can do for example network on the main thread. So need to do it in another thread the interact or first wheel Enqueue the request with the network client Let's say that we're using retrofit so it's going to incur it and After that you're going to go to the repository and put the data there. So this was like a synchronization We use oh, it's going to call first the interact or to give it back the The data that it took from the network and then the interact are going to put it in the repository So it was like a synchronization between the work with first of all I need to get Actually the data from the network and only after that I can put it in the repository So after that the interact or will go to the UI and the UI finally can start to observe the data from From the repository so we have like two models. We have the observation which It's going to be pushed to the UI every time that the change is going to be in the repository and Very in the beginning of that we have like the synchronization I need to do this first and only then I can do the other job that they need to do All right, so what is coroutines? Coroutines is basically just a piece of code that can be suspended and resume in Kotlin each coroutine is going to be compiled by the it's going to be changed by the compiler to a state machine and each suspendable place it's a separate a suspendable function is going to be Like a state in the state machine It's very old concept causing didn't invent it. It's basically Start at some times in the 70s. There is like Implementation of that we've see C++ scheme and not even with some more more than languages like C sharp and go long What really nice about the coroutines that the compiler in at least in the case of a Cotton the compiler is going to hide from me all the complexity and the code inside the coroutines can be sequentially and it's really nice Kotlin support coroutines starting from One point one point one. It's still an experimental mode, but it's not because they just Thinking whether or not to kill it. It's because they want to polish the API's before we're going to declare it as release So it's okay to use it In Kotlin there is like suspendable function which mark with suspend function and only core only coroutines can run the suspend functions so Like I told you before there is like suspend function each one of them actually is going to be translated to some state in the state machine and By that we can get gain the nice readability with coroutines And most of the coroutines that written by jetbrain. It's coming from this extension library It's called a Kotlin Kotlin X coroutines and it's really open source and everybody can Can contribute to that they do accept external pull request So let's see coroutines in practice so like I told you I working in a company which called get in the mobility area and and among other services, but we have we have like pre-prereouts Which was pre-defined like fixed routes and anyone can various like cars that going along the along the line along the line And everybody can just pop in and pop out from the from the car and we have also integration with application Which called city mapper? With city matter your city mapper provide us the lat and the long of like the GPS coordination of The journey that the user want to do and we need to do a lot of things We need to calculate what is the fastest walking path to the for the to the line and from the line And where we need to go and when you need to go off and There is a lot of things that we want to do and we want it's going to be smooth So for that we need to gain some performance in addition We have like there is like the green dots there, but it's the walking path and we're going to change to convert the GPS coordinate to the to actual address like a string and a lot of things that we want to do and we want to do it as fast as we can So for now we're going to deep dive just for the conversion of the GPS location the lat and the long to string so for in this case we have like a Function which call and the deep link it's getting the request everything that he needs reside inside the request and Everything that's going to go back to whatever call it. It's going to be in the response so first of all we want to take the start lat long and to Convert it like a string and the same thing with the Atlanta lat long and by that we can just put in the UI the addresses instead just to give and Now a location So this is how we're going to do it in synchronous in synchronous word way We're going to do the first one and after that we're going to do the second one But I can actually do it in parallel. So in core teams I can do it like this in parallel I Going to first explain what is the launch core teams or lunch? It's called. It's a function. It's correct in function Which gets a lambda? Everything that inside the lambda is going to run immediately the launch return a job structure that's called a job that I can do several things with him and And eventually what is going to happen here in the code is going to run the first one and the second one It's going to run in parallel Now the second thing that they're going to show you here. It's the run blocking when I want to wait for something to happen before I'm going to continue with the With the execution I'm going to put it inside block of run blocking The Join that we're doing inside the run blocking its suspend operation. This is actually suspend function and this is how the The compiler know how to turn you know how to translate it and because of that you can just put it like that We don't need to give some callbacks for that So it's really nice. It's working, but I Want to make it a bit more readable So I can just wrap the launch Coroutines with my function which I call it in parallel because for me it's mean a lot and It's going to get just a task Instead of doing the run blocking inside the code that going to introduce like extension function for list of jobs Which will do that actually the same thing. It's going to take everything inside the list and join So it's going to wait until all the jobs inside this list will end And finally I want also this task will be bounded to some life cycle And I can do it very easily by introducing something that I call it job counselor, which is also life cycle observer so When I when I just Initialize this this class this job counselor I can register a career register it to some life cycle Owner so it will be aware to the life cycle On destroy those of these lifelife this life cycle I will just go go over each one of the Jobs in the list and I'm going to cancel it by that it's going to be bounded to life cycle All right, so with these abstractions my code look a bit nicer for least for me Now I kind I it's it's written I doing two things in parallel and Then I go in to put all of them with the job counselor It's so it automatically will be closed when the life cycle will be destroyed and Finally, I'm going to wait for all All right, so it's really nice, but now I have like a different problem. I want to make Two tasks to run in parallel, but just take the first one of them for example Let's say that we have two providers that know how to reverse geocode from a lot long to some string One of them is Google and the other one is my best friend Startup and I want to help him so we're going to use both of them So now because instead of using the lunch coroutine, we're going to use a sink a sink. It's doesn't like unlike Lunch it doesn't start the execution right away It's going to wait. I turn we're going to do a wait or on a wait in this case And it's returning defer which defer it's something that extend the job, but it can also bring me back like value So I going to have these two sink blocks and then I want to wait for the first one So first of all we're going to look at on the select select. It's another coroutines that know to select the first first one of these jobs that will end first so We have like the first provider that we're going to await on it on the second provider and When I going to call to on await, it's literally going to start the work in their sink And with that the first one that will finish probably of course not Google. It's going to be my best friend the startup We're going to get a result and this is going to be actually the return value and Because we want to wait for the first one we wrap all of that with one blocking. So once again, it's walking It's really nice, but I want to make it more readable So what I can do like before I'm going to provide my own abstractions I'm going to wrap the sink call with this call that's called with this function. It's called fetch address with provider All this select code it's going to be wrapped in extension function this time instead of jobs of defer jobs and They're going to call it first a wait for first And now I can use my abstraction in the code look much more nicer I have like fetch the first one first fetch the second one put all of them in the job canceler because I still want to be bound to the life cycle and Then I'm going just to wait for the first one So it's much more nicer much more elegant than before so Until now we just saw examples of Synchronization between two jobs that we want to wait for the first or do both of them in parallel Let's see how can we observe things with coroutines? So in coroutines there is this notion of channel channel. It's like It's like a message queue that's which can connect between it's like network between two coroutines and Basically, China's have some capacity So let's save it the channel have capacity of two if I want to write something to the channel and It's fully fully occupied. So I'm going to be suspend until Somebody will pull something from this message queue and if I want to receive something but it's empty So once again going to be suspended and wait until Somebody will write to the channel in this case We're going to use special channel like it's a broadcast broadcast channel, but it's not just a broadcast channel His capacity is confluent what it's basically mean that we're going to have a lot of subscribers which can or consumers which can start to consume this channel Everybody of them going to get when you're going to first to observe the chains you're going to get the latest value and When I update a new value all of them get the same the same value so we have this broadcast channel and I just call it like a walking in for stream. I going to take from the network the walking path and then I want to put the initial walking path so the y can start observing things and Like I told you before send its suspend operation. So I must wrap it with coroutines and And after that I going to call some function which will do the calculation with the location and update the The walking path every time that something has been changed and we're going to return it as response In the UI side what we need to do we need to get this broadcast channel open subscription This is the way that we open like a new a new subscriber. That's going to To be notified about the changes and Then we starting to consume it now are using here a while because I don't want to get only once the value I want it's going to be of there all the time. So we're going to use this while the channel is not closed and I get something if it's not now I'm going to push it to the channel and then everybody that's listening to this channel Can take it and do it it whatever you want But it's very complex so I going to introduce additional abstraction of my own So this time I going to start with the data stream So that a stream is just something that gets a subscription subscription from type of receive channel and And I going to introduce their like two methods one of them I call it notify on change which basically hide all the boilerplate that I had to do in order to consume values from the to consume values from the From this channel and I going to have for that close because if I don't want to observe any change anymore I can just close it With that I can just Use another abstraction which called data store and that is so right for me the Brought us the broadcast channel And the varies like a set current value which do everything that we need to do with the lunch and shutdown and In the bottom we have like the get data stream which remain return for me the data stream from the previous slide and With that my code is look On the end of deep link it's looked it's look a bit nicer because I don't have to put the lunch there and It's nice, but when I'm consuming This events it's look much much more elegant now All I need to do is just to take from the response the walking path of data store Get the data stream and be notified on change and do something with this change All right, so why coroutines and Especially why coroutines when we have other libraries like Rx Java So this example, it's not mine. I took it from some jet brain slides But it's really pin the point that I want to to make clear like we have your Example of two codes that we need to write both of them doing the same jobs. We have like user that we're going to to get some Creditionals and do login after we're going to do the login we're going to get like a user ID and with the user ID we're going To load some user data and we're going to show it so in the Rx Like in the left side We're going to declare the login as a single and the load user data as a single and Spoiler every time that you're going to use Single you need to think maybe it's not the right tool for what we need to do because In this case all we need to do is just to synchronize between things so the code is look like that We have the login with conditional flat map to Load the user data we on on success. We're going to show the data. We need to subscribe on that on the right on the right side It's not just the right side. It's actually the right side So everything is going to be Sequentially because we're going Like I described it to you are just going to do the login Get the user data and show it and it's much more readable at least for me Besides that why to use coroutines so The code inside the coroutines get can be expressed sequentially I Can build my own abstraction. It's very easy to do it. So the code will be very Readable for me and my team and everybody every new guy that will come to the team It will be very easy to him to jump in and start coding there is a lot of Integration with other major frameworks that's coming out of the box from Jetbrain like we've are X1 and are X2 and Java 8 streams and it's very easy to write additional one if you want and we have some talks about multi-platform and Jetbrain indeed working on on porting the coroutines to other platforms so there is right now I think already Implementation for JavaScript and they're working also on native so in world of multi-platform it could be very nice way to do a sync code in In in the common libraries that we're going to have and with that I want to thank you if you have any questions. So I'm going to be around and Thanks a lot
to talk about a synchronous code with Kotlin want to do and we want to do it as fast as we can