droidcon SF 2018 - Taming WebSocket with Scarlet

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi everybody thanks for coming to my talk my name is Trisha I'm a software engineer at tinder before I get started how about we have some fun right everybody raise your hand if you love superhero movies yeah great most of you are like me and raise your hand if you don't know who she is she's Scarlett Johansson that of the Black Widow from the Avengers unfortunately we're not going to watch a superhero movie today however I'm going to show you something just as awesome we will be talking about Scarlett a library we created at tinder that makes WebSocket on Android as simple as ten lines of code has anyone used WebSocket before cool WebSocket is a communication protocol between I mean for real-time applications it creates a persistent connection between client and server just like a phone call it's bi-directional the client can send messages to the server the server can also string messages down to the client let's see it in action here's how you will create a WebSocket connection in JavaScript you can listen to when a connection is open and send a message to the server you can also listen to messages from the server and process them that's pretty cool right however if you're new to Apps target or its alternative you you'll probably be wondering when it's WebSocket useful and what problems does it solve ultimately how can WebSocket help you build a better app well it really depends on your business requirements and how real-time your features need to be most apps work fine without a real-time connection the server however if you are building chat location sharing or online games you'll probably appreciate having a real time connection like WebSocket a tinder we started using WebSocket last year it helped us deliver matches and massive messages faster and more efficiently to all of our users on Android iOS and web before I show you how WebSocket made tinder a better app let me introduce to you how in their works cleaner is the most popular app in the world for meeting for meeting new people we sparked millions of connections every day when you open tinder on your phone the first thing you'll see is a stack of people nearby that we think you will be interested to meet you can tell us whether you are interested by swiping left or right a left swipe means you want to pass and a right swipe is alike let's swipe right on scarlet - like her and if scarlet also likes you then it's match you can start a conversation immediately if Scarlett has already so I brought on you however if you are the person who swipe right first your profile you will show up on your her app very soon and you'll receive a match when it happens since we already have a match let's start chatting eventually if you enjoyed chatting with each other you might go on the day together as we have seen swipe match and chat constitute the core tinder experience in order to deliver the best inner experience our app needs to get new matches and new messages for our server in real time how does the tina rap do that in the beginning we started simple that makes a request to the server every two seconds to ask ask for updates if there's no changes on the server the server will return an empty response I did have the app we'll check back later every two seconds however if there is a new match it will be sent to the client the next time he asks this form of communication is called polling polling is easy to implement in code it's I mean it's probably not the best practice but it worked for a long time during this time tinder group is user base as financially we now have users in almost 200 countries and we deliver 26 million matches every day at tinder scale the cost of polling is prominent our server is flooded with requests from millions millions of devices because each device makes a request every two seconds after running some numbers we found out that 90% of the requests get a 90 response what does that mean it means that all these empty responses are unnecessary overhead although they do not carry any useful payload they have a long list of headers that cost server CPU and bandwidth if we can avoid making those requests we could downsize our server and save a lot of money besides the cost issue polling also has a longer latency if you make a request every two seconds no matter how fast your internet is you could experience a two-second delay because pulling is expensive and it has a longer latency we decided to move to switch to a push model and our back-end built a new infrastructure that can push new matches to the app using the push model the client can subscribe to the server and measures will be sent to the client through a persistent persistent connection there are a lot of technologies out there that can be used to push data to the client for instance there's web socket socket IO and MQTT we chose web socket which is widely supported on all the platforms we develop for Android iOS and web compared to long polling web socket is much faster messages are delivered instantly in the most efficient way because we only consume the bandwidth needed by the payload ok let me get some water so last year around this time I was given the task to integrate the new web socket API in our Android app as I mentioned before I'll use the this WebSocket connection to receive new matches from the server so that our users can see them as soon as possible I also used the web socket to send and receive chat messages let's take a closer look at the tinder app here are three views that are driven by real-time data when the app received receives a new match the its match screen on the left is launched the match list which is in the middle this plays our displaces all your matches we show the new matches on top and the matches you have already talked to on the when the app receives a new match I hope it'll be added to the top of the match list finally we have the chats view on the right which involves sending and receiving messages from the server okay let's explore how chat view interacts with our web socket API in the high level the chat view is consisted of three sub views a recycle of view that displays the conversation and that de text where the user can compose messages and a send button they sent the message to the other user the view logic of this chat view is encapsulated by a view model the chat view model has three properties it has a live data that provides messages to be displayed on the recycle of view since we don't want to user just send messages when there is no internet connection we use a is connected live data to disable the send button when the wrap is offline and enable it when the connection is back in addition when the user clicks on the send button the view will call the same message method on the view model this is all pretty straightforward but to feed these life data we need a WebSocket libraries I mean we need a WebSocket library there are a few options available and we chose okay HTTP okay to the HTTP added WebSocket support in 2017 let's take a quick take a quick look at it is web socket API to create a WebSocket connection using okay HTTP you will use this method it takes two parameters the first one is the request which contains the server URL the second one is a listener object you can use the listener to listen to the connection state and you can also use it to listen to incoming messages to send a message however you use the WebSocket object now that we have a view a view model and okay HTTP let's see how they interact with each other here's the data flow diagram that represents the chat view and what's happening behind on the Left we have the UI and on the right we have network let's see what happens when a view is attached to the view hierarchy the view model will try to open a WebSocket connection using okay HTTP and after the connection is open the view model gets a call back from the WebSocket listener and it updates the is connected live data to be true which then sets which then enables the send button and when we receive a incoming message from the other user the view model will receive the message from the WebSocket listener and then it will update the message live data so that the recycle of you will have the new message after a user has composed a message and hit the send button the send message method on the view model is triggered and the message is forwarded to okay HTTP these are all the interactions between components it's easy to understand right that is not correct it's a nice it's a naive implementation because it did not take into account connection failures as programmers we tend to focus on the happy path and overlook the edge case WebSocket is straightforward when the connection is open however things can get complicated when you need to recover from connection failures a WebSocket connection can fail for many reasons it can fail when you are on the train passing through eternal it can fail when a server is out of memory and tries to release resources let's take a look at the happy path the on on this diagram the horizontal axis is time and the vertical axis represents the connection state when the user is not in the app we don't want to open the connection as user opens the app we open the connection and keep it open as long as the user is in the app this is simple and straightforward right so what should we do when the connection fails let's take a look at this error scenario so the connection is opened however the server crashes for the fourth second what should we do with the kind sure because the user is in in the app the client should try to retry the connection again and again until the server is back on right in order to implement this retry logic we need a timer the timer has a simple API you can schedule I would try and get a callback using the timer listener given the connection is open this is successfully and the send button is enabled by the view model the connection may fail at any time and the real model would then have to disable this important right and as it does that it also schedules a retry with the timer and a couple seconds later the cop the timer takes and the view model gets a callback and opens the connection again with the retire logic you can Scarlett I mean we can keep the connection open and all the things we need to do to keep to implement retry is here unfortunately this is good for the web but it's not good enough for Android apps on Android we don't want to keep a connection open at all times according to the developer guideline we should only use the connection and we should close the connection when the app is in background in order to be a good citizen and saves users battery in order to react to activity changes and I mean lifecycle changes we can subscribe to a lifecycle owner such as an activity or fragment or the app we use a lifecycle listener to listen to when the connect when the app is in foreground when their app is in foreground the view model will get a callback and opens the can action is usually what ok HCP when the view I mean when the lifecycle owner is when the app is in backward however the the view model will get also get a callback and closes the connection using web site the WebSocket object supposed to the app is in foreground again and the connection fails right all right no worries the real model will schedule a retry and it will bring the connection back on suppose the connection fails again the view model retry schedules another retry but this time the app goes to the background what the view model needs to do is cancel the timer locate all these asynchronous events that you need to handle just I mean to add WebSocket to your app I know where you guys are thinking you must be lost right this is exactly how I felt on my first day at tinder two years ago we had this giant singleton manager objects made out of thousands of lines of spaghetti code let's take a look at the chat view model again the view model is overloaded with different responsibilities guess how many lines of code this I mean this view of your model has I think it will take at least a thousand lines of code to write in Java and thousands of lines of spaghetti code to add WebSocket to your app in 2018 that's exactly the motivation behind scarlet we created scarlet to make WebSocket is simple on Android instead of having a giant view model that takes more than a thousand lines of code you can leave the complexity to scarlet and write the chat view model in just 10 lines of code okay so so what is scarlet exactly scarlet is the first WebSocket library that minimizes boilerplate code and spaghetti code that you need to write scarlet is declarative you you only need to describe what your endpoint looks like and scarlet will implement it for you let's continue the chat example using scarlet here's the code you need to write to declare your end point you need to declare an interface and use scarlet to create an implementation of the interface just like in retrofit let's go through the methods one by one to send the message to the server you need to declare as a method that has sent annotation and specify the object you want to send which is the message in this case after you create how do you create a implantation of this interface using scarlet you can use this method to send just a message to the server to observe connection States however you would need to create to declare a method where is the receive annotation and the return type will be a flow of webs of WebSocket event after you created a implementation of this interface you can subscribe to the if a nation-state and Locker to be able to receive incoming message it is similar you only need to change the return type to the message type you expect from the server and you can after it's the server's is created you can subscribe to it just to recap we created an interface with three methods and use scarlet to create an implementation let's use it in the chat view model right and we have a messages life data I mean you know - we can simply convert the incoming message string - we can aggregate the string to become a list and show and the view will then be able to consume the messages and for the is connected or live data you can simply transform the lives WebSocket event and [Music] hazard to the client finally we have a center sent message method which delegates to the chat servers just to recap we declare three methods on the interface and we use scarlet to generate an implementation then we created a view model in just 10 lines of code besides being declarative scarlet is also modular meaning that it consists of more modular components that can be changed independently to see how modular scarlet is let's dive into its implementation as a WebSocket library the sky needs to implement the WebSocket protocol and it uses okay HTTP under the hook instead of using okay cheap HDTV directly we created a well-defined interface around it and this interface hides the specific WebSocket implementation from scarlet it enabled I mean so that scarlet can work with any web socket libraries that you that you prefer just to clarify scarlet does not have a code dependency on okay HTTP instead it uses it as a plugging in order to keep the connection open for you when a connection fails scarlet schedules it uses a retry timer internally and you can customize the back of duration using the back of strategy plug-in again where the connection fails as correct uses the back of strategy to determine when to retry next in order to close the connection when and stop retrying when the app is in background scarlet listens to the lifecycle owner and it's this is also done done using a dependency inversion so that scarlet can be a pure cotton library and it does not have to depend on android life cycle has to state a life cycle in scarlet has two states it has the name as the one in Android argued hydro components that they are different a life cycle house scarlet when to when to connect and keep retrying when the life cycle is on and the connection failed scarlet will keep retrying these plugins allow scarlet to take over state management from you so that you don't need to write any spaghetti code the real benefits of having plugins is that no matter what library you prefer to use you can use it with scarlet for instance in tests you can use the mock HTTP server which lets you let you mock this server behavior and of course you can also write your own plugging plugging are easy to write because they are designed to be customizable if you are if you write your own plugin someday please create a PR and share it with us similarly backup strategy is also a plugin we have a few built-in implementation and you you can write your own as well for life cycle we have built-in support for Android and you can use you can write your own ripes lifecycle and you can read you can also reuse them by composition I'll get to this later okay so let's see how you will create a Scarlet instance in code if you're starting from scratch like we just did here's the recommended configuration first create a scarlet builder and add a WebSocket plugin that is based on okay HTTP then you can choose the backup strategy you prefer I we have a default one and and then you can use to scope the website connection in you can use our built-in Android lifecycle plug-in which which only opens the connection when the apps is in foreground and here we go here's how you create the website instance for the chat view however something is missing here so how did Scarlett know about how to how to serialize and deserialize messages and do you have to use flowable it turned out that Scarlett has to two more plugins for customizing these behaviors let's go back to the list of plugins Scarlett supports using Moshi jeezum and protobuf to do data serialization this is done through an interface to call message adapter the message adapter has two methods it takes your data one takes takes your data and turn it into the the data structure that I mean that the class that you want and the other serializes a class to a string or bytes as we saw in the previous example Scarlet's supports flowable for extra rx Java it also supports co-routines and this is done through string adapters which enables Scarlett to support any asynchronous abstractions that you prefer and Scarlett is able to support these behaviors without any code dependencies on those libraries because we use them in your system as plugging so how do you customize message adapters and stream adapters all you need to do is to add them to the scarlet builder once setup you will be amazed how easy it is to maintain scarlet let's say you want to make chat more engaging by adding a typing indicator feature you'll I mean how many lines of code let me guess how many lines of code we need to change to be able to send typing indicators to the server we only need to change two lines of code like this similarly switching chosen library is also a one line change all you need to do is has a different plug-in to the Builder and attender our website connection is only enabled when the user is login if you want to further Scout them scope down your WebSocket connection to when the app is in foreground and the users login you can do it in less than 10 lines of code first you can you can you first grab to building lifecycle plugins that describes when the app is in foreground and write your own life cycle plug-in that represents when the the user is login then you can simply combine these life cycles and Scarlett will only connect to the server when the app is in foreground and when the user is logging let's drive it in the function and pass it to the Builder cool Scarlett we have seen how Scarlett is declarative and modular usings because of that using Scarlett in using Scarlett makes your code base clean the is Scarlett reason well-written and maintainable in other words is called written in predictable code the answer is yes although state management is complicated on Android Scarlett is not written in spaghetti code it's actually very testable and debuggable because is uses immutable immutable States and it has a state machine internally we actually wrote a column this as DSL for writing the writing declarative state machines which is available as a separate library let's take a detour to see what a DSL look like this is a water state machine we all know that water has three dates three states it can be solid liquid and gas and there are four possible transitions between them let's model the state machine in Cartland first we need to declare all the states and then we need to declare all the events which triggers the state transitions next we can use the state machine DSL to declare the state machine a state machine has a initial state which is solid when the state is solid and the it receives a hot melted event a road transition to the liquid state when it's in the liquid state and it receives a unfroze event a would transition to the solid state and similarly we have you you can declare other transitions like this and it's simple and readable after a me is simply readable but it's and is also testable after the view at the state machine is created you can assert the initial state to be solid and you can also test the state transitions given our melted event we we just saw how declarative the state machine is here's the state machine Scarlett uses internally it's simple and elegant and it's customizable to you this is how the uses the lifecycle changes to keep the connection open and when the connection fails it uses the back of timer to recover the connection this is yes this is the state management is correct let's move on and just to recap Scarlett is declarative and makes WebSocket as simple as ten lines of code it's also modular you can use any web socket or json library with Scarlett Scarlett is also predictable because it's driven by as immutable state machine since Scarlett was released in June we received a lot of feedbacks from the community the most one is feedback the most one if wanted feature is supporting more protocols we are working on a v2 to address this need supporting most different protocols is challenging because they are very different for instance not every protocol is bi-directional server-sent event for only allows server to string message ten messages tend to down to the client but not the other way while web socket and service' event only have one channel other protocols supports the concept of topics and it which behaves like message queues and for for instance if you're building a chat app again you can have a new message topic for incoming messages and maybe a user account topic that notifies you when a user joints or or leaves the room finally we stomp and in cutest MQTT do not talk to the server directly they talk to message brokers which then forward the message to the server to your back-end in order to support or all these libraries we made a lot of changes in scarlet we rewrote half of the code that is in scarlet and let's take a look at all the plugins scarlet has here's what we did in scarlet v2 we climb up the ladder of abstractions and we talk the and hook the WebSocket plugging the WebSocket abstraction and turn it into a protocol client so by doing so we're able to support any persistent connection protocols available okay unfortunately we don't have time to go deeper into the details but I would love to discuss with you later after that after the talk the source code here is available on this branch and it's being published to jetpack as you can see we have different pull different artifacts in in v2 and please check out the demo app we have added servers that event and socket IO to the demo app here's this here's this sneak peek in just scarlet v2 and I cannot wait to discuss it with you offline and that's pretty much all I have for this presentation just to recap scarlet is declarative I mean it's easy to get started for beginners is also customizable for advanced users because is predictable I mean sorry because it's driven by a state machine you know it's all so predictable and finally Scarlett's is evolving we are the other protocols to in in addition to a WebSocket I hope scarlet and can make your life easier and here's how you can get started today and I'll be around today and tomorrow and few feet feel free to grab me and check out and please check out our booth we have a thinner booth in a lobby yeah I'm happy to that's it I'm happy to take any questions [Applause] you
Info
Channel: droidcon SF
Views: 1,508
Rating: undefined out of 5
Keywords:
Id: 3zidyfA2VlY
Channel Id: undefined
Length: 43min 6sec (2586 seconds)
Published: Sat Dec 01 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.