A Journey From Complexity: Reducing Technical Debt

23 May6:00 pm – 6:30 pmStage: Execution StageTalk

Checking session availability…

Hang tight while we load the latest updates.

What is complexity?
• History of complexity ( Backend, Backend to frontend, Frontend and back again )
• Microservices curse ( how the frontend start aggregating )
• GraphQL aggregating
• Microfrontends approach ( break down complexity )
• Serverless to rescue ( reduce complexity )

A Journey From Complexity: Reducing Technical Debt

Fabrizio Fortunato at UXDX Community: Dublin. Video: https://youtu.be/zPO1wzasn7M

Readable transcript: edited from the recording's captions for readability (fillers and false starts removed, punctuation and section headings added). Wording is the speaker's own. Timestamps are positions in the video. Names marked [?] could not be verified against the audio.

Introduction: an odyssey through complexity

[00:00:05] Hi everyone. Thank you all for the introduction. I also changed my title in the meantime since the presentation was announced. What I'm here to talk about today is complexity, and generally complexity in web development. First, let me introduce myself, just to reiterate: I'm Fabrizio Fortunato, lead front-end developer at Ryanair Labs. This is my Twitter and GitHub handle, and you can also find my blog, where I generally speak about web development. So let's start.

[00:00:36] "Sing to me of the man, Muse, the man of twists and turns, driven time and again off course, once he had plundered the hallowed heights of Troy." This is how Homer starts his Odyssey, and this is how I want to start our odyssey, our journey through complexity.

[00:00:52] Let's start with the meaning of the word complexity. Complexity means the state or quality of being intricate or complicated. It derives from the Latin complexus. If we look at the usage over time, this is from Google, what you can see is that in the 1950s the word really starts being overused. I don't know if it is a coincidence, but in 1954 the first programming language was released, Fortran. So I do believe it's actually developers' fault, this overuse of the word complexity.

[00:01:25] The first driver of complexity in web development is business logic. Business logic is the part of the program which encodes real business rules. It dictates how business objects interact with one another. We can generally represent it through a flowchart. In this case, I want to search for flights. I'm going to input my dates. If there are flights available, I'll display the flights; otherwise I'll suggest different dates. This is a simple business logic that we can encode.

A short history of complexity and page weight

[00:01:58] Now, after the introduction, we are ready to go on our journey, the first step of our journey. We start off with the history of complexity, because I believe it is important to know our past in order to understand the present and predict the future. Web development started in 1991. That's when the first website came along. Through that decade, from '91 to 2000, the average page size was 14 kilobytes. We weren't talking that much about complexity. The only thing that we had was the dancing baby GIF. That was web development during that time.

[00:02:41] The next decade, from 2000 to 2010, was marked, for example, by the release of CSS 2. We started paying more attention to UX, and by this I mean generally designing glossy buttons. That's what we were doing. The average web page went from 14 kilobytes to 100 kilobytes.

[00:03:06] The current decade, from 2010 till now, was marked by the coming of new modern JavaScript frameworks: Backbone at first, then AngularJS. HTML5 also came along during this decade. The Ryanair website also went through different transformations, three actual websites during this time. This is because all these changes were fueled by an increase of complexity in web development, and we needed some tools to actually handle this complexity. But this didn't reflect well on performance. In 2010, the average webpage was around 470 kilobytes, and today the average webpage is 1.5 megabytes.

[00:04:04] Now, I know I'm correlating complexity with average page size, which is not entirely true, but for web applications it is actually a good metric to look at. I want to stress why page size is important. Let's take an experiment; you can find this one if you Google "impact calculator." Let's say that our website loads in 3 seconds, and we have an average of 1 million users, with an average order of $150 and a conversion of 2%. If we manage to increase our speed, to decrease the page load time by 1 second, this is the potential revenue that we are looking at: 1.3 million. And this is not just some kind of game. Amazon reported that if they slowed down their website by 1 second, they would lose roughly 1.6 billion per year. That's why it is important.

Services complexity: backend for frontend and GraphQL

[00:05:14] During this talk, what I'm going to talk about is different areas of complexity in web development and how we can try to reduce them. We start off with services complexity, the interaction between front end and back end. Historically, complexity was only part of the back end. The back end was the monster, and the front end's responsibility was just displaying things, or glossy buttons, right? The communication was very simple, one-to-one. This kind of back end is what we refer to as the monolith. Now, I know this is not the kind of odyssey that I was speaking about, but I really needed to put it there.

[00:06:06] The monolithic architecture started to be, let's say, destroyed, or shifted into microservices, back in 2011. What it means is that the back end started using a collection of different services, loosely coupled and independently deployable. Our application became a suite of different services. But if we rephrase the law of conservation of energy: complexity cannot be destroyed. It can only be changed from one form to another. What it meant is that now the aggregation, or the communication between all these microservices, was done in the front end. In our case, we have to deal with, for example, flights, accommodation and car hire. We can also see this if we look at the average total number of requests over time: it has increased over time.

[00:07:08] What we're experimenting with in order to reduce this complexity is the concept of backend for frontend. Basically, it's putting the aggregation back where it was supposed to be. What we gain by using this concept is that we are reducing complexity in the front end, because we're shifting it back to the back end. And remember, for complexity on the front end, the ones who pay are your users. We can unify data models between the different microservices. And also, if you have different clients, you're going to use this business logic, these services, across, for example, your Android application or iOS application.

[00:07:53] A perfect match for this is GraphQL. GraphQL is a query language for your API. What it does is model your business domain as a graph. You define a schema, and it uses very powerful declarative data fetching: the client directly specifies what is necessary for it. Let's have a look at our basket services. This is still what we're developing now on GraphQL. This is an example of the schema. We have a basket with a total, and the items inside the basket, which we call components. The total, for example, has an amount, a currency, and whether it includes taxes.

[00:08:40] Let's have a look at how we can use GraphQL. What we define in GraphQL are queries. In this case, I want to get my basket, and, if you see, I'm only interested in the total. We wanted to display only our total here in our queries. In another example, we also want to display our items inside. What we do is just append to a similar query that we also want our items, our components, in our basket. This is the power of declarative data fetching. You always specify exactly what you need. There's no over- or under-fetching.

Breaking down the front-end monolith with micro pages

[00:09:29] Now, we were discussing the back end shifting into microservices, but what about the front end? Well, the front end by nature is generally a monolith, mainly for performance reasons. The other thing is that different frameworks, like React, Angular and Vue, don't talk very well to each other. They don't really work together that well. What this led to is a high exposure to technical debt, similar to what the back end was experiencing before shifting into microservices.

[00:10:08] To give you an example of this, the Ryanair website is a single-page application built in AngularJS, and we're talking about more than 300,000 lines of code, only the front end, with 75 routes, which translates roughly into 75 pages. We're not talking about content pages. These are heavy application pages with heavy business logic. What we realized is that scaling up teams and software is hard. When you have more than 10 distributed teams working on the same code base, this is hard. Since there is no clear division between the teams, everyone is responsible, so in the end no one is actually responsible for those changes. To sum it up, we can't write software fast enough with a monolith.

[00:10:59] So what's left for us? It's to break down the monolith. I know, not the same effect, though. Where can we start? Let's look at our pages as an example. We have our home page, our flight select page and our products page. What we can do is split them up into different applications, so each page is its own application. This is what I call micro pages.

[00:11:31] In this sense, a micro page is an independent page that can be developed and deployed independently. They are loosely coupled, so they only know what the next page is and probably what the previous page was. Although they are loosely coupled, it doesn't mean that we are reinventing the wheel over and over in the pages. We are using a set of shared components that we can use across the pages. So this is basically all the characteristics that microservices have, applied to the front end.

[00:12:08] It also gives you a way to break down your monolith iteratively. You don't need to release all the pages at once. You can take page by page and start introducing these micro pages. It's basically the concept of a single page application per page, which I know feels like you're underusing the power of single page applications, but this is necessary in order to reduce your surface of exposure to technical debt.

Design complexity: from responsive to adaptive

[00:12:41] The next one is design complexity. Over the course of the years, we've seen different approaches to design come along. We started off 5 years ago with responsive web design, based upon the concept of fluid grids, media queries for hiding and showing content, and also flexible images. With responsive web design, basically, we designed for desktop and then scaled down to mobile.

[00:13:10] When we realized that mobile traffic was increasing and that scaling down was difficult, we reversed this approach. We started using mobile first. This is an example on rooms to go trainer.com [?]. That's what we used. But this actually wasn't good enough for us, because this way we basically doubled our complexity. We had two completely different interactions, sometimes also two completely different designs, between mobile and desktop.

[00:13:42] That's why we started using an adaptive solution. What it means is that we develop only for mobile and only for desktop. What it gives us is two independent flows, two different applications, which are very performance oriented for that specific device.

Infrastructure complexity: serverless

[00:14:05] Okay, the next step, or actually the last step, in complexity is infrastructure complexity. I know that when speaking about front end, you're generally not involved and you're not responsible for the infrastructure, but I do believe that our code is running somewhere, and we need to know how this code is running. So what we'll look at here is how we can decrease complexity in our infrastructure also.

[00:14:36] Let me introduce you to serverless. We define as serverless any application or service that relies on third-party services, like, for example, S3 for object storage, or Google Cloud Functions for running your code in the cloud. Why is serverless very good in our case? Because not only are we reducing complexity in our teams, but we are also offloading the blame to someone else. Moreover, as I was saying, a front-end developer shouldn't be responsible for looking after servers. They should be responsible for caring about and writing user interfaces. This is an example of all the topics that a front-end developer needs to know during a normal day of development, and I don't want serverless to be on that list also.

[00:15:30] An example of how we use serverless in Ryanair is for hosting our solution. We use S3 to store our files and then CloudFront, which is Amazon's CDN, to serve them. What is our responsibility? Just to upload the files, like you would be doing with FTP, and then Amazon takes care of the rest, scaling up and everything.

[00:15:57] Another example is Lambda functions, functions in the cloud; in this case, Brotli compression. Brotli is generally a better compression algorithm for the web. It generally performs better than gzip. This is the list of the browsers that support it now, with the usual offender always there. So we need a way to actually support a fallback. Can I ask you a question? Raise your hand: how many of you use Brotli in production? No one? A couple of people? Okay.

[00:16:35] What if I show you how easy it actually is with serverless to start using Brotli? It's just a few lines of code here. We are intercepting the request, we are checking the headers, and if the browser supports Brotli, we serve the Brotli compressed file; otherwise we fall back to gzip. Why is this important? Why does this mean a lot to us? Because just by doing this, with a few lines of code, we are reducing the application footprint by 23%.

Ryanair 3.0 and the results

[00:17:07] To sum up all of these practices, all of this journey through complexity, what I want to present to you today is what we call Ryanair 3.0. We actually just released it last week, just in time for UXDX, I would say. This is our first step, our first page towards the micro pages architecture. We started with flight select. Ryanair 3.0 is an adaptive solution. It uses the micro pages approach and also leverages serverless a lot.

[00:17:45] What we started doing, especially in Ryanair 3.0, is paying special attention to performance, which translated into going from 2.2 megabytes for the current solution to 572 kilobytes. This translates into a first meaningful paint going from around 15 seconds to 6 seconds. Another metric we're looking at is that the current flight select, in an online mode on a synthetic metric, takes around 10 seconds, while the new flight select takes around 1.5 seconds.

[00:18:28] So, as I was promising you, we want to make our users happy again, and this is our first step. But I do believe that we are still far away from Ithaca, and that's because reducing complexity in web development is a never-ending journey. I want to leave you with Occam's razor: entities are not to be multiplied beyond necessity. So keep it simple.

Q&A

[00:19:02] Host: Thank you so much, Fabrizio. I mean, Ryanair must have an awful lot of technical debt, but it sounds like you're managing it in a really incredible way.

[00:19:11] Fabrizio: Lots of work actually going on, and loads of people actually handling all of these things now. It's very much a collective effort.

[00:19:18] Host: Yeah. We do have some time for some questions. We have a mic that is ready to be passed around. Please put your hand up if you have some questions. We have one here in the front.

[00:19:31] Audience: Hi everybody. Thanks, that was really interesting. Two questions, really. What way are your teams set up? Are your UI people in cross-functional teams? And the other one: would these pretty drastic changes be applicable to every company, or is it just because you have such a scale of users? You've made some huge decisions there. Would you recommend that to everybody, or is it just because you have so many users?

[00:19:56] Fabrizio: Okay, let's start with the teams. Generally we have more heterogeneous teams, so you will have front-end developers, back-end developers and all the different roles in the team. We believe that the team should be autonomous and able to take a feature from development to production. As for these steps against complexity, I think part of it you can definitely take as a recommendation, like using Brotli, for example, or another case would be GraphQL for handling your aggregation. But other things, like adaptive, or the micro pages approach, are specific to our use cases. With adaptive, in the end, you're going to handle two applications, so it brings you a different kind of complexity that you have to manage. While the other one, micro pages, was mainly because we wanted an iterative way to break down a monolith, and this is what we came up with.

[00:21:11] Host: Excellent, thank you. Any more questions? One in the back there.

[00:21:18] Audience: Hi. You said you support your micro pages with a set of shared components. How do you manage those shared components so that the complexity isn't transferred into them, and they're kept easy to use and don't become specific to something?

[00:21:36] Fabrizio: Yeah, this is something that we always debate between the teams. Starting off with visibility: everyone needs to have visibility of these components in order to understand how they work. So creating all the tooling around managing those components is important: to release them, to publish them, etc. After that, our way to keep it simple is that we generally don't start from the generic; we start from the specific. For example, if we take one of the micro pages that I was showing, it's inside the micro page that we developed one of the common components. Then, when we see that another page or another flow needs it, we try to extract it. So instead of starting from the general, we start from the specific and then go to the general.

[00:22:32] Host: Thank you. Any more questions? There's one. Oh, you've got one.

[00:22:35] Audience: How's it going? I was wondering if, by taking a micro pages approach, you could possibly incur a higher performance penalty from pulling down a large payload for every single app, for every page. And if you did experience that, did that sway your choice of framework to something with a much smaller bundle size as a result? How did you approach that?

[00:22:58] Fabrizio: Okay. First thing: yes, we actually considered that there is going to be a hard refresh between the pages, so we'll have to deal with it. What we're looking at, for example, is starting to use server-side rendering intensively. That's one thing that, hopefully, and I don't make any promises, maybe by the end of the year we're going to have something for. Besides that, our reasoning was the following: it's easier to split our application and then try to put it back together, rather than starting another time from a monolith approach.

[00:23:42] Host: Great, thank you. Still a question down in front here?

[00:23:49] Audience: You talked about serverless technology and the fact that developers shouldn't need to care about the server hosting of their application. There has traditionally been a different train of thought, where developers need to know and be part of the DevOps team, and have DevOps members within teams, because sometimes there are issues that you only see in production or production-like environments that can be very difficult to find or debug otherwise. Do you have a similar experience, or now that you've moved to serverless, how do you debug in production when you don't have those environments or look after those things locally?

[00:24:23] Fabrizio: Yeah, this is something that we started mainly a year and a half ago. We started introducing DevOps into our teams, letting the teams take more responsibility for this rather than throwing the ball to another team, the infrastructure team. What came out of it was that a lot of the front-end developers didn't have the necessary knowledge or skills to look after scaling services, or write configuration for Linux machines, etc. That's why what we worked on was trying to find the simplest approach we can take to put our things out in production, and that's why we decided on serverless. Regarding the environments, we use AWS a lot. You've probably seen it in the examples. It's very easy to replicate production-like environments across your different accounts.

[00:25:20] Host: Thank you. Any more questions from the floor? I've just spotted one.

[00:25:34] Audience: Thanks. I was wondering about your policy to design just for mobile and desktop. We did the same recently, prioritizing those two viewports, but when it came to testing, the tablet design wasn't acceptable, which meant the tasks had to go back into the team to be reworked, which caused frustration all around. Have you experienced the same, and how did you address that?

[00:26:00] Fabrizio: Something similar, not actually the same, because generally tablet traffic is not significant enough to justify a solution only for tablet. That's why we are still debating whether to use the desktop or the mobile version for the tablet in this case. But generally, tablet traffic is not so significant that we are looking to create a tablet-specific version.

[00:26:34] Audience: Thank you.

[00:26:35] Host: Excellent. I think that's all the time we've got for questions now, but if you'd all give Fabrizio a big round of applause.

Speaker