Server Driven UI, Tom Lokhorst (English)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi welcome to my talk my name is Tom and you may know my work from any of these apps that I've worked on and in particular for this audience you may know are the Swift a tool for generating static resources for your Xcode project this talk is about serve driven UI and in particular about my experiences using and building it for prime phonic brand phonic is a classical music streaming service it has apps for Android iPhone iPad a web player a service integration and if you're familiar with Apple music or Spotify it is similar to those but it also has additional features that are specific to classical music we built transonic over the course of a couple of years and we used server from the UI from the very beginning let's look at a quick primer on what serve driven you is this screen is from the brand phonic app and shows a composer page the screen is built up out of several components at the top there's the artist header there are two section headers three detailed buttons that link to other pages and a text with a couple of paragraphs of text the order of these components as well as their contents are all driven by the server that means that if you want to change something say we want to show some albums instead of the biography we can make that change on the server and we can release this without having to ever release any new versions of the clients you may have heard about this ID before and in fact it's not a new ID here are just a couple of examples of other approaches to the same concept Airbnb has Lona their server driven UI framework a couple of years ago Spotify used the app framework they have since made some significant changes and ten years ago Apple had a presentation at WWDC about using server-side pee lists to configure your iOS application and of course the web it has always been served Riven in 91 it was probably all static HTML but since CGI HTML has also been dynamically generated let's look at some differences between a traditional architecture and a server driven UI in a traditional architecture you have a client that sends a request to a server the server then responds with some JSON that the client has to render in a servant referee server driven UI you have a client that sends a request to a server the server then responds with some JSON that the client has to render ok so to the untrained eye these may look very similar but the devil is in the details and that's what this talk is about now that was a bit of a global overview let's dive into the details I want to talk about five different topics how to build screens and components using this approach how to do navigation how to perform actions both locally and remotes how to do API design and integrate it into the application and finally when is it not appropriate to use this approach and maybe should you use something else first off let's build some components we'll start small with a uitableviewcell this shell shows a single work by Beethoven piano sonata number 14 in c-sharp minor opus 27 number 2 also known as the moonlight sonata this looks simple but of course there's a lot more to it than that looking at the domain model we see there's a ton of more details for each word there's a separate title and number a key an alternative key an opus number genre a period and some translations now this domain model lives on the server in some database there's a record with a lot of fields which of these fields do we send to the clients do we send the whole objects or do we only send the data that is needed and where does the decision live how to render this who decides that the key has to be in the first line and the opus number has to be in the second line we reserved Raven you I this is all very simple all these decisions are done on the server this is all the data that is sent from the server to the clients just the title and a subtitle because that's all that's needed in this design obviously in a real world app there's a lot more details here are a couple of variations of that same screen or same components in some cases who want to show the composer name next to the work and in other cases who want to show the number of recordings of that work again we can do this in a server driven uy the jason has a bunch of extra fields all of which are optional so the clients only shows a certain field if it is filled in and the server has full control over what to fill in and when and what to show when in the app here's a different example a table fuel cell that shows an artwork again all variations of our models in Jason here's a bunch of different fields all of which are optional what's interesting here is that the format of the Jason is pretty much is very much influenced by the interaction design of the app and in fact when we were developing this app for the first time the interaction designer the backend engineer and the app developer were all working together closely to discuss the different variations and both the Jason model as well as the visual design were developed simultaneously for final component let's look at something a bit more complex this is a carousel it lists the top composers in order of popularity and we implemented this as another table view cell but this one contains a UI collection view looking at the Jason for this we see that the component is of type carousel and there's item type which references to the type of the items in the carrot in the collection view so we know for the collection view what sells to DQ the items themselves are objects in the items array and those again only contain the title and the image because those are all that is needed to render this specific UI taking it all together let's look again at the composer page to render this page we need to do one single API call this API code returns all the data that is needed to render this whole screen at once so going from the top we have the type of this page a component screen a title a header an array of sections and each section contains an array of components again this whole page is implemented as a UI tableview controller and each component is a UI tableview cell the data that is needed to render that UI tableview cell is all included in the original jason ok second topic navigation a topic that comes up quite a lot when talking about an app that uses data from a server is when do we fetch that data how do do we do navigation so looking at these two screens we see a screen that shows the list of Composers and when we tap on it we want to show a single composure on a separate screen but when do we do the API call so naively might think of two approaches one is she tap on the screen you go to this second view controller and that starts loading the data or to you tap on the screen it does the API call immediately and then you have to wait for it to complete and then you can go to the second screen we don't want to do either of these approaches because one we didn't want to have the web browser effect where you always go to a whites page that then slowly loads data and secondly we didn't want to have navigation be slow when it's happened something you immediately want to see something happening so the way we fixed this is to include the header for the second screen as parts of the link in the first screen so let's take a look at that here we have screen recording and I've enabled the network link conditioner to make the network connection seem slow so I'll tap on the second item mozart's we go to the screen it's now loading data and here the data returns let's look at it again I'll tap on Mozart we immediately push the view controller either this view controller is doing the loading and now it shows the data so there are in fact three states that we have to deal with the first screen that contains a link which includes the header for the second screen and when we tap that item we immediately push the second view controller that view controller is in a loading state and it already shows the big header with a loading animation below and finally the third States is when the API call returns and we fade in all the data let's take a deeper look at Jason for the Mozart item in the composer section there's a title and an image as we saw before but there's also an action that action already contains the type of the page that is will navigate to so we know what few controllers to loads it also contains the URL for the API to call and get back all the other data and it has an header the header is the exact same type of header that is used at the top of the second page so it contains the image and a title and a subtitle one interesting aspect here is that an image doesn't just contain a URL it also contains a low-res URL a low-res URL is used as a placeholder if that image happens to be in the HTTP cache it is shown while the bigger image is being downloaded and what's interesting here is that we use the same low res over URL that is used in the previous page as the URL for the item in the carousel so very often when we navigate to the second screen the item is already in cache and we can show something as a placeholder you may have seen my coke let's talk from two years ago where I talked about the Rijksmuseum art fewer there are two we use the same approach where we use the low rest tiles as placeholders while downloading a high resolution version of those tiles so in practice when tapping items in a carousel we see a nice animation to a second few controller when the top half of the view controller is already filled in with a nice background image and the lower half is being loaded still if we look at this composer screen itself we see a list a list of works and if we for example look at a first work eine kleine Nachtmusik if we look at a Jason we see an action and this works very similar it also has a header but this is a different type of header but all the this header doesn't include an image but all the behavior is still the same so if you look at the screen recording we check on the first item we go to the second few controller and and the data loads in in general we are quite happy with this approach it is a bit of work on the server side to be able to generate all the headers that are exactly the same as the header of the target page but once you've done that you get back this great benefit of having a very smooth navigation that doesn't show all these interruptions all the time moving on let's talk about actions the most obvious action you might expect from an app like this is playing music so when we tap on the first item in this list the mini player pops up and the music starts playing how does this work with a server driven UI so the track is a type of component that contains all the information needed to render that component it has a title a subtitle and a duration but it also has an action this action is of type play it contains a track metadata URL which is the URL that when called returns a complete cue of all the music that needs to play in order but similar to the header in navigation it also contains a track Star Trek and that objects contains the information needed to immediately start playing music so we don't have to wait for that metadata or alcohol to return a different type of action that we call our actions that we call remote commands actions this we can see in the menu in the top right the Jason for this menu shows a list of actions for each action has a URL and a payload that payloads needs to be sent to that URL using an HTTP POST when we tap the first button here ads playlist to favorites we see a loader that loader shows up while the API call is happening and it blocks any interaction with the user interface when the API call completes we see done and the page behind it is being refreshed now that the page is refreshed if we tap the menu again we now see remove playlist from favorites it's worth noting here that everything is very generic in fact when we first started implementing this feature on the backends we implemented favoriting having a database and all that but we also implemented the user interface completely on the backends so this is all driven by the backends there is no client-side interaction needed this feature was built and shipped completely from the backends although later on we improved on it here we see a second type of response at a serving and sense instead of just showing a big done the server can also ask for more information for example by showing a multiple choice list or like in this case asking for user to type in some text here we see a part of the playlist creation and editing workflow this whole flow is built and orchestrated completely on the server without needing any code on the clients apps now there are some things that can't be done on the server some things need deep client interaction for example the play action we saw before but also sharing here we see is share button in the top right and when we top that tap that the system share sheet pops up for this we need client-side logic so what the server sends us is very very basic it just sends a title and you can a universal URL the clients get to decide how to interpret the share objects in the case of the iPhone app it shows a share sheet button in the navigation bar and it uses the URL also for handoff between different Apple devices and finally in case you were wondering if we left in that ugly at-at favorites in the menu no we also included a nice-looking button that's when you tap it becomes filled in and in theory the way we could have implemented this is you tap the button and completely in the background we do an API call and preemptively already make it a button be filled in and if the API call returns with an error then we have to unselect the button again and all that we didn't quite get there yet in prime phonic so it has a nice button but when you tap it you still see the full screen loader but at least the button looks nice already next I want to discuss the specifics related to API design and how we integrated it into the app as you can see we use API versions and after two years after release we already have 15 different versions of the API but that's not a big problem API versions are cheap we introduce a new API version whenever we add a new component type but some client existing client doesn't know about yet so when a request comes in the server looks at the version of the API and then decides how to respond to that so if for example an app requests on page but the app is an older version using an older API and on that page is some fancy new carousel item the server has to decide how to deal with that component it can for example decide to fall back and show an boring old list there or it can simply skip the whole component if it isn't that important that that old client sees that as I said before next to the gets request we also have post requests where the server or the client can send a body in a post and that uses the same versioning mechanism again this screen uses a UI tableview controller it uses a difficult data source to reloads and animate the differences when reloading this screen when a remote command returns we also use HTTP etext to ensure that if there's nothing changed on the server then we don't need to do any animation and the same goes for if the clients cancel a request for some reason we also don't animates JSON parsing is all done using Swift's codable we creates trucks that exactly match the API types if for some reason we need a different model domain model between the API types and the views then we create a separate type for that and we do manually map between the API types and domain model it should be noted that the server needs to support a bunch of different API versions but the clients do not flying clients only ever need to implement one API version so if we in some API version deprecated a specific components then clients can just throw away that code they never will receive that again from a server one thing you may have noticed is the value or decoding error in the components array in the top struct this is there to prevent against program error in theory the server should never send something back that the client doesn't know how to handle in practice programmers are humans too and people make mistakes so we have something for that so the value or decoding enum is a safeguard it's a generic enum that wraps a single value or an error the decode decodable implementation tries to parse the inputs as the wrapped type and if that decoding fails then it returns an error otherwise it returns the actual value what that gives us in practice is that parsing doesn't stop when the json decoder encounters an error so for example if we're trying to parse a menu that has an array of buttons if in the json one of the d jason has four objects and one of those four objects isn't actually a button or can't be parsed as a button then parsing still continues after that one and we still get back a menu struct and if we look at it we see three buttons in there and one decoding error and the clients can then decide what to do with that in the case of prime phonic what we mostly do is lock the error and skip the item and still show the other three buttons and in practice that has already saved us a couple of times where if someone made an error and it wasn't called in testing finally one interesting aspects of certain UI is that we can not just do an online experience when clicking through the app would also build an offline experience using it so when you're online the app is in the background always downloading a offline version of the of all your data of all the albums that you've marked as being available offline so that when you're offline you can browse through all your offline albums and still see all the data that was originally generated on the server that brings us to when he served revenue I'd not appropriate for the last year I haven't worked on prime phonic so I asked one of the current developers about his experiences with server driven UI and one of the examples he came up with was the offline experience he said the single JSON response for the offline version became too large and well the initial development went very fast because of the reuse of existing components for the offline page we needed a to sense the danger for everything not just the first page but all the subsequent pages as well and it turned out that became too large some users had 20 megabytes big jayson's that needed to be synced all the time and so they switched back to a more traditional API so in this case service revenue I maybe wasn't the correct approach after all to other things in the app that aren't implemented using chef-driven UI are the music player itself and the subscription flow both of these are deep OS integrations so when you're playing music the music player needs to update it now playing screen on your iPhone you can use your airports as remote controls and you can control the app from your Apple watch or from carplay that's all very deeply integrated into iOS and the same goes for the subscription flow that uses in-app purchases and that's again deep and specific logic and finally here's an example of a completely different app as an example when not to do serve driven UI this is the reaction with a map another app I've worked on and it allows you to walk tours in the rack museum and listen to audio descriptions and it sends you from room to room and it shows you the right audio descriptions for the artworks in that room in this app almost all the logic is done in the clients so the client downloads one big JSON file that includes all the tours and then when you walk around and the app uses Bluetooth and beacons to figure out where you are and all that is done in the client so even though the data about which tours exists come from a server this type of app really serve driven UI doesn't make any sense and that is the end of my presentation I hope you now have a better idea of what a serve driven UI is and how we've used it successfully in the prime phonic app I've shown some implementation details and when maybe not to use it again my name is Tom locust and I've recently quit my job so I'm now available for something if you want to start a startup to build a cool mecco X app contact me if you know something else interesting sent me an email okay for the people watching life I'm now available for questions you can ask questions in either the YouTube chat or in the cocoa head select channel thank you for watching okay I think I'm live now let's see I have some questions already as I said you can send questions in the YouTube chats which as year and in the slack channel and new whom has collected some questions let's see Ezekiel asks we are working on a survey from UI framework here in Brazil cool which uses a back-end for front-end to integrate your data API with surfer UI my question do you guys use some kind of backends for front ends or the original API was dedicated to serve live in UI we built up everything from the ground up so when we started there was nothing so we build up a whole music classical music database and everything so we build a back-end for front-end and we've built it with the very idea of doing survey of UI so bass itself is generic so we could use some other build some other API on top of that spotty at the only API that currently exists this server driven UI for the user interface who asks do you have any compatibility strategy that what would happen if the server suddenly returns an item type that care cell components that's not support it's an older version yes and he added later that question was already answered so yes we do have that failure error so you are decoding error type so that helps what we mostly try to do is if we can be for it's compatible so sometimes we have a carousel and when we want to create a little variation of it we add another field to it so that the older apps just used original version and the newer apps get that you do the it little variation so that we don't run into this issue but if if there is a if we do have to make a backwards compatible breaking change then well the server sites should handle it and if it doesn't their client will be racially skip that item Bruno asks have you ever dealt with a preview not responding to not running well too what could conceivably change the entire app from a lot under their noses after approval did you anticipate and maybe prepare for this during developments even if it wasn't necessary we did discuss it during developments briefly but we didn't really prepare anything for it partly because Apple had the exact same talker ten years ago about how to use your piglets to surface sites drive your your iOS app and also any app can always change something after after it's been reviewed if there is a server behind there somewhere so yes we serve revenue why we can completely change everything but if we wanted to do that we could do that in any way using any any sort of approach can always have a boolean Alma server somewhere that says now show the other screen so we didn't really expect Apple to care about this and in practice this was never something that came up during a preview anton asks will so if you I change the way you do server revenue I yes and no so when we built this originally through phew I didn't exist when so if your white came out we looked at it and said well is it fantastic for this approach as I said for the past year I haven't worked on a Panasonic so I don't know if they have started using it yet but if I would still be working on it I think it wouldn't fundamentally change anything because our whole approach was use components that can be reused and so we could just drop in three fui for each of these components and it couldn't really change anything drastically so not really I think service with UI fits perfectly well ticket to asks any thoughts about site fast feedback flows for example input validation that typically typically try to avoid stock to the server to keep super quick response times yes so you saw the way we have these generic menus for adding favorites or changing playlists and yeah anything that has to bounce from the server back and forth doesn't really work so this doesn't really work that nice I mean it works it works fine but it's the user experience isn't very nice so the best thing here I think is navigation for navigation this is perfect as soon as you start doing no log collections or local actions also work like start playing music the sooner she has to do non-local actions wave to talk back to a server then there's this delay and a spinner or loader or something but those aren't very nice but in general this is this episode consumption app so you browse through things and you play music so that general flow works very well if you have highly interactive things it wouldn't work wouldn't work all the time so the things like creating and editing playlists which isn't something you do very often you know won't be creating playlists very often so we do use the remote commands there but yeah chef-driven UI isn't isn't the correct approach if you have a tight local action the key to also ask how do you establish shared language of UI building blocks with designers so that new features can reliably we built using existing building blocks so yeah that's really when we were developing it we worked together very close with the designer and we built everything together so the approach we had or the way we worked actually was very nice the designer would create a sort of general idea of what he had in his mind but then he sent over this half-finished piece of design to the developers and when the developers got to implementing it or one of the developers specifically one of the clients whoever was first either Android or iPhone or web then the designer would sit next to the developer and talk through all the details and typically the as I said the the designer and one of the app developers and the API developer were working together on a new feature so do all things at the same time let's see I see I have one more nodes which is not a question so if anyone has any further questions ask them now if not I have to wait for the delay oh you're actually another question whom you how do you decouple the business logic from the iOS side to the backends what is the backend looks like to generate these jason's sure else understand the question so the oh dear it depends on how you interpret business logic so what's interesting here in this app more so than any other app that I've worked on is that the app them app itself doesn't know very much about the domain so the app knows about the general concept of a component page but in the domain there are things like albums or composers and that sort of thing but the app doesn't know about that domain at all it only knows about components and all that domain knowledge lives on the server and the server the backend for the contents knows how to change what's a composer is and how to change that into components so that's interesting and in general I like working on do main things in when I'm developing apps so in this case I worked a whole lot on the backends instead of the app which I usually work on because now all the fancy domain decisions have to be made on the back end instead of on the front end other than things like playing music which is all front-end work let's see is yeah that's the question already so yeah so find a question time be quick because with the delay I'm gonna quit quit soon so I don't see any more questions in that case thank you again very much for watching when is typing Alondra typing to the NA Artic thank you okay yes thanks so much for watching as I said I am available for something so if you have any cool ideas about using Apple technologies to build something fancier contact me and thanks again for watching goodbye you
Info
Channel: CocoaHeadsNL
Views: 3,806
Rating: undefined out of 5
Keywords: CocoaHeadsNL, CocoaHeads, iOS
Id: ERPmUsLkwEE
Channel Id: undefined
Length: 37min 15sec (2235 seconds)
Published: Mon Jul 20 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.