 Good morning, everyone. It feels great to be here. We are really excited to present our journey of how we build housing.com, the mobile version. OK. So I'm Rahul. I lead the front-end team at housing. As the name suggests, we are into home buying. And for most of our users, home buying is a once-in-a-lifetime event. And it's a long journey before they settle for their dream home. We have native apps to facilitate that experience with native performance, better re-engagement, and offline experience. But we also had a few challenges, like poor internet connections, mostly 2G and 3G, and low-end devices in terms of computation, memory, and storage. These kept our users from downloading our apps and thus hindered our business to reach their goals. We also had our mobile website, which looked something like this. The problem with this was it was a monolithic code base, having desktop and mobile tangled together. And the components were kind of bloated because of the e-files in JavaScript and the media queries in our CSS. That eventually affected our performance. So we thought about we have to cater the growing need of our mobile user base. And we chose to upgrade our mobile website to something that can compete with our native apps. The reason being simple, web has better discovery and a wider user base than any other platform. Also, the cost of bringing a user to our mobile web was 50 times cheaper for us than bringing the same user to our native apps. So it was the deal breaker. We started off building our mobile website. The first and the foremost thing that we had was to support all the major browsers that are out there that our users use on more than 2,000 different devices that they have. So this was our first aim. And then we thought once we have this part done, we'll upgrade that experience to compete with our native apps. So we built Housing Go. And we were happy with the kind of metrics that we saw. We were able to bring down our page load times by 30%. We were having 10% longer user sessions. And the bounce rate was cut down to 40%. On top of all this, the most important part was 38% more conversions on our mobile website. That really helped our business realize the goals much sooner and effectively than earlier. And yeah, I'd like to call up on stage Ritesh, who will be taking us through the journey of how we built this. Good morning. So I'm Ritesh. I'm a front-end developer at housing.com. So let's talk about how we actually built it. From the start, we were focusing on four key areas. The first one is that we wanted to deliver assets fast. Then we wanted to bring down the time to first meaningful paint. And also the first JS-enabled interaction time. And at the same time, we had to improve the experience of our returning users. So most of the other performance metrics actually depend on when is your asset delivered. So this is a waterfall of a traditional website. First, your whole HTML loads. And then other asset request goes. So you have to wait for whole HTML to load before making a request. So when you analyze your code, you'll find that there's a certain part of your code that needs no computation or no API request. So let's talk about HTML streaming. Now, this is how it looks like on client side. First, we send the initial chunk that only contains the code that needs no computation. You can see there's pre-connect, pre-load, and the critical inline CSS. Now, sending the pre-load, we actually start the request for critical JavaScript earlier. We'll talk about them. So now, this is the full HTML. After the server has made API requests and it has received all the responses, it sends all the HTML. Now, this has body, initial one didn't had, and this has all the content. Now, the size of full HTML is around 15 kb, but the first response that the server sent was around 4.2 kb, this is it. So pre-load. Most of the time, the developers already know that a particular route is going to need a few critical resources. You can load them in advance. And so by using HTML streaming and pre-loading combination, we were able to start the request for critical JS much earlier than other assets. So after we were done with asset delivery, we went ahead to improve our render time. And by render, I mean the first meaningful paint. Now, the difference between first paint and first meaningful paint. On the left side, you see that that's first paint. First paint is anything. When there's anything, any pixel available on your phone, most of the time, that's not relevant. And user feels like waiting. And when the relevant content is there, that's the first meaningful paint. Now, we wanted to zero down the difference between these two. So we experimented with server-side rendering. I am saying experimented because you should always measure before you implement. So this is a traditional app shell model on first load. Till 2.2 seconds, there's a white screen of death. You have nothing to see. Then there's a state where you have something, but it's not relevant to the user. He still has to wait. And around seven seconds, he sees the first meaningful content. Now, the region before 2.2 second and 7 second is what we call the loading screen of purgatory. So the user doesn't know what's going to happen. He may receive the content. He has to wait for a certain amount of time. And if there's any error, he will have to wait in that state forever. So we wanted to improve this. We wanted to remove this totally. So this is after SSI enabled. Now, when we implemented server-side rendering, the first meaningful paint happened at 2.3 seconds. And that was quite an improvement. And all these tests have been run with a web page test. It's written on the bottom. So there's also a bonus when we implement a server-side rendering that the basic meaningful content is available for everyone. I mean, as Raul said that we have users using more than 2,000 types of devices. And so there are a variety of users with different browsers. The versions may be older ones. So the basic content is rendered for all of them. So that's a bonus. So till now I've talked in bits and pieces about how we improved JS-enabled interaction. But the main thing that you need to do for improving JS-enabled interaction is that you need to ship less code, less JS. So less of the JS, faster will be the interaction time. Now, when you ship less code, you will have to lazy load resources on demand. And this brings us to code splitting. We are using Webpack 2 for code splitting. And we do both JS and CSS sharding. So generally, the chunks that we make, we divide them into two categories. The first one of them is route-based chunks. Now, when a user lands to a particular route, first we make a call for the main JS file that you will require. And in parallel, we make a request for the corresponding CSS file. So when the CSS file has been loaded, we allow the navigation. And after his idle, we make a call for the next probable route that he might navigate to so that when the user navigates to that route, the transition is almost instant. So next, I come to the second category. That's intent-based chunks. Now, these are the chunks that are only required when the user does a particular kind of interaction, like scrolling or click, and doesn't involve any route change. Now, let's take an example. This is our listings page. Now, on top right, you can see a notify button. Now, by analytics data, we know that this is a kind of button that gets clicked once in a few sessions. And the corresponding view that it requires has, it's of 32 kb unzizip. So it makes no sense to load that with the main JS bundle because most of the times, it will go unused. So we require it only when the user has clicked on that particular button. So after doing all this, currently we are at a stage where our first meaningful paint happens at around 2.3 seconds. And the first JS-enabled interaction starts at around 4.2 seconds. Now, by JS-enabled interaction here, I don't mean the DOM content loaded. We have defined a custom metric. Like, we calculated this when the component actually mounts. Like, since we are using React, for us it is actually component-did-mount. So this is the time when the component-did-mount gets triggered. So I've talked about how we push critical resources using preload. We have improved render using SSR and inlining critical CSS. We are pre-caching assets using service workers, as Rahul will tell you. And we are lazy loading resources on demand. So we are very much near to what the purple pattern promotes. And so till now what I have discussed has improved the experience of first-time users. Now, we also had to improve the experience of returning users. So I'll call back Rahul to tell you more about that. So as I told you, finding a dream home is a long journey. User comes online multiple times to make his searches, to compare the houses he's seeing, the property he's seeing. So it was very important for us to make a compelling returning user experience so that we make that journey as smooth as possible. We use service workers to pre-cache a few resources on install and act as a proxy for our subsequent network resources so that it can serve them from the cache directly when it's requested second time. By doing this, we have been able to bring down the first meaningful pain that happens for a first-time user at around 2.2 seconds to 700 milliseconds. And the first JS-enabled interaction from 4.2 seconds for a first-time user to 1.1 seconds. We also implemented add-to-home screen features to give users the access to instantly interact with our app directly from their home screens. And we implemented push notifications. I like to mention that the kind of conversion rates that we are having from push notifications are almost beating a few of the channels that we have. So that's one thing that's taking us closer to our apps. The offline navigation, this was important for us because whenever a user visits for the actual site visit, the properties are generally at the outskirts of cities where the network is very flanky or absolutely no network. So this experience helped them to actually revisit their session or re-look the properties they have already done on the mobile. We used credentials management API to keep our users almost logged in virtually almost every time so that their information is synced across devices very smoothly. So once you are done building the app, the main question that we had is, how do we maintain this? We have done a lot of things to maintain the first pain time, first JS-enabled interaction time. But as the product evolves with a lot of features, it's very difficult to keep in check these metrics. So we came up with our own system of continuous integration with Webpack and WebPace test. And we made it as easy as just putting a label on a PR in GitHub. So if you are done with your code and you raise a PR, you just need to put a label run test and we'll put out all the information that needs to track these metrics right on the GitHub PR. Like the chunk sizes, it helps a reviewer know that how this PR is changing or modifying the chunk sizes that we already serve. The few route-based statistics like the first pain when versus speed index of the few of the critical routes that we take care of. Also the network and the timeline view. This helps the reviewer get an essence of what resources are loading and how they are loaded. So I think this was very important to us to close the loop of the complete development from the development and maintenance. It's not always, we are yet to do a lot of things to make the app faster. And one of the thing that we are experimenting is moving from React to Preact. We have seen that in our initial prototypes, moving from React to Preact has brought down a difference of 120 to KB in our vendor bundle. And that's huge, like that's around 700 to 800 milliseconds of JS enable interaction time gain on the client side. We are also experimenting with AMP to let our users have almost instant experience when they come through Google results page. So thank you. Thank you all. Hello, over here. Hello. Jake, are you there? Yeah, Paul, I'm here. Okay. We were asked to do a quick handover so we've cut the bit where we walk on stage. That was housing.com. And here's Lyft. Yay! Well, good morning, everyone. I'm Malcolm Ong, product manager at Lyft. And here with me today is my colleague, Mohsen Azimi, lead engineer on our project. And we're gonna tell you a little bit about our journey of how we built our progressive web app at Lyft. So just show of hands, how many of you have taken the Lyft before? All right, there are a lot of you. Awesome. Well, for those of you unfamiliar, Lyft is the fastest growing on demand transportation service in the US. It actually came out of a hackathon project from our original product, Zimride. And so similarly, our ride.lyft project also came out of a company hackathon. And so certainly in the very beginning, when we came up with the idea, there was a lot of internal skepticism as to why we would build a web app at all. Could we, if we did, could we actually build a web app that would be a viable alternative to our native apps? And certainly this makes sense because historically, Lyft's been a native mobile first company, has invested a lot of time, resources, et cetera, on the native apps. And so we said, well, let's go ahead and take a stab at it and see what we come up with. And I think we're pretty happy with our work. This is a desktop view of the app that we built. And our hackathon project gathered enough internal excitement that we said, why don't we go out, go ahead, go out, try to productize this and see if our users would also be just as excited. And so some of the reasons why we built this, from our standpoint, a PWA could be a great supplement to native apps for various reasons. Number one, greater reach. So essentially allowing a lot of our users that are unsupported or on aged-out devices to use Lyft. Number two, reduced friction. So certainly pushing users through an app store funnel is very, very inefficient. And number three, faster uploads and experimentation. So let's talk through each of these. So greater reach. On the pie chart that you see on the right, approximately 8% of iOS users in the market and 3% of Android users will soon be unsupported as we slowly deprecate older OS versions, right? So our progressive web app allows us to support these users. Furthermore, 100% of Windows Mobile and 100% of Amazon Fire devices, for example, simply because we never had Amazon Fire app until our PWA. And we still don't yet have a native app in Windows Mobile either. So this allows us to support these users. And in addition to this, obviously it reduces a lot of operational costs, technical costs, resources, because it means less code and potentially less incidents or support tickets. Number two, reduced friction. So as we all know, sending users through an app store funnel is highly inefficient. There's high drop-offs, high cost per installs. And so the funnel that you see on the right there, we can potentially go from six steps, right, starting from web entry, all the way down through the app store, towards sign up and finally a first ride. So it's been said that every step of this funnel, you could essentially lose 20% of your users. And so what are the reasons for this? I mean, maybe it's because, I don't know, users don't like the permissions that you're asking about. Maybe it's because they don't have enough storage on their phones. They have all those Snapchat videos that they saved. So we can basically change this to the three-step process, if you will. So in other words, imagine the PWA can replace the white portion of that funnel. Another interesting thing is deep linking. So imagine we had a developer partner app like Google Maps, and Google Maps has integrated Lyft, and they wanna send users to a seamless experience from Google Maps to Lyft, right? Right now, if you don't have the app installed, it sends you to the app store. Very, very, not as seamless as it could be. So deep linking from developer partner apps straight into our progressive web app is a much more seamless experience to do that. And finally, faster deploys. So certainly deploying fixes, code, experiments on web takes hours, not weeks. There's no need for this app-approval process, if you will. And so running experiments faster, AB testing, and certainly our app is always up-to-date. Have to constantly update your app. And in terms of productivity and timeline, our team actually just started with just basically one engineer, Mohsen. And our alpha MVP that he built was built on top of an Angular stack, primarily because Lyft's historically been on Angular. And we were able to do that in roughly two months' time. And so we proved that our PWA had a lot of promise, right? We, of course, ate our own dog food, used a lot of our, leveraged our public API to hand a lot of server-side things, had a little bit of support from design and QA. But for the most part, this was pretty quick compared to developing an native app. And so once we quickly proved the potential of this, we got enough internal support to get more engineers on the team and worked on a new app, a beta version of this, from the ground up in React, and was able to do this in roughly one month's time. And so now I'd like to bring out Mohsen to talk a little bit more about the technical aspects of the app. Hello, everyone. I'm here to tell you a story, a story about a ride. Meet Valerie. She just saw DJ Khaled is giving undercover lift rides. So she wanna try, maybe, he's her driver. So she goes to lift.com. And what we have in lift.com is this big pink button that says request a ride. We don't force users to download the app. They can just request a ride right there in the app. This is really important because if we force them to download the app, they had to download almost 75 megabytes of data just to start. So this is where PWA wins. You might think, okay, if she downloads the iOS app, it's gonna be a better user experience. It's gonna load faster. But in fact, our PWA loads faster than iOS app. This is under LTE network with a good device. But with slower networks and slower devices, we get good results, acceptable results. So now that she's in our PWA, she needs to sign up. For sign up in lift, we ask for your phone number and a payment method. If you have your web payment set up, you don't need to put in your credit card. Just use Android payment API. So she can do that. With two tabs, she has an account and she can pay for her ride. When she requests a ride, oh, I forgot about this. I talked about how the PWA is a better user experience. And that means in any front, animations, anything is same as the native app. Okay, so now that she wants to take a ride, when she taps request ride, what we do is we register the service worker that listens to push notifications from our servers. So if her driver is coming in two minutes, she can put her phone in the pocket and wait for the driver to come in. When driver is here, we send this push notification that lets her know that driver is here. This push notification, do another thing. It has a payload that updates the ride information in our app. So that means if she taps on this push notification, we are gonna take her to our PWA without making any network request because push notification had all the data. When she's done with the ride, we also send the push notification. That push notification as well includes ride's information. So even if she's offline, she can open up our PWA and access this screen, which has all the information about the ride, who the driver was, how much it costs, and things like that. This is really cool. But it doesn't stop here. Thanks to Background Sync, she can submit her feedback while she's offline. When she does this, what we do in the service worker is we are making a post request, putting it in the cache, and then service worker is gonna wait for online event. When that happens, this post request is gonna be submitted. This is without her interaction. It's happening in background. I think this is really, really cool. So making this progressive web app was a really, really interesting journey for us. We are doing it for about two months. It's very early, but we learned so many lessons that I want to share a few of them with you. As other speakers here told you, less JavaScript is better. As much as we love to add new libraries and new dependencies to our code, we should always be consider about the amount of JavaScript we push to our users. This is really, really important for mobile users. Your regular MacBook Pro that you develop on is way more faster than the phone that your users are using. That's why in Lyft, we are using real devices for development and testing. We forbid ourselves from using our Macs or these powerful computers for development. It's not the most pleasant experience, but that's a user experience we are working on. Another thing that we did was minification. I'm sure all of you minify your JavaScript, but we did something new, which is thank to Angular team with their TypeScript to Closure Compiler annotated JavaScript project. With that, we were able to minify JavaScript even further. A method name in minified regular minification process will not change because JavaScript doesn't know where this method is being called, so it can't rename it all over the place. But with TypeScript and Closure Compiler, we were able to minify it even further. The other thing that we did with JavaScript was tree shaking, which is now much easier than before with Webpack and the new minifiers. Here's a quick look of our technology stack. You're not using a lot of dependencies, as I said. Just react a little bit of Webpack and things are working pretty great. Our bundle size is less than 40 kilobyte GZ. Thank you. We had challenges doing this work too. The biggest challenge was the other platform. But at the same time, all these PWA APIs are pretty, pretty new. And sometimes we saw MDN documents are out of date. There is not much stack overflow questions to look for. You just ask questions, you can get answers. So that is an interesting challenge to have. The other one is not in our control, so hopefully that's gonna be fixed next year. I have one little lesson we learned, and that is animation for opacity. If you use CSS animation for opacity, infinitely, it's gonna crash your browser. Don't do that. So now I'm gonna hand it over to Malcolm to talk about business impact of this PWA. Thank you, everyone. All right, thank you, Mohsen. And so putting this all together, what was our early business impact? The initial response from our alpha was certainly very, very positive. We exceeded our initial weekly rides, number of weekly rides goal by 5X. We were able to launch a app essentially a wrapper around our PWA into the Amazon Fire App Store very, very quickly. And if you're interested, there's a link up there to learn more. And finally, we estimate that we'll have up to a 50% improvement in force upgrade churn. So this is, again, folks that we eventually have to force upgrade due to having lower or older OSs. And so next steps, this is certainly still a very, very early beta. We're still iterating on it a lot. It will be buggy, but we encourage you to try it out. Number one, for next steps, we definitely like to prove and optimize our conversion funnels. Number two, experiment a lot. And number three, finally start adding a lot more features onto this so that we can actually reach feature parity with our native apps. And so I want to thank everyone here for listening. Some of our team members will be here at the conference later today to answer any questions you might have or just chat. And if you'd like to give it a try, just go to ride.lift.com. And in fact, we have a coupon code for you to use for 20% off your ride. All right, thanks, everyone. Thank you.