Azure Portal: The Largest Single Page App in the World
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Jedryszek, Jakub
The Azure Portal is one of the biggest, and most complex Single Page Applications (SPA) in the World. Are you curious what’s under the cover? Let’s check what tools, frameworks, libraries and techniques are used to enable over 500 developers to work on one web application, and having possibility to release a new version anytime. In this session I will uncover all details of end-to-end development process, performance tweaks, and how we implemented Continuous Integration, and Continuous Delivery.
 Thank you. Thank you. Good afternoon. Thanks for coming for my session. So my name is Jacob. And I work for Microsoft. And you can find more information about myself at my blog at JJ09.net. I encourage you to subscribe even if you would like to. I came here for the nicest city in the world in Seattle, in United States. It's really gorgeous there. Anybody here have been in Seattle, maybe? How did you like it? Okay. Just for recording purposes, like, entire audience say they like it. Actually, I live in the city of Redmond, and I'm a cyclist. And before I moved to Redmond, I didn't know that Redmond is like the best place on earth for cyclists. We have over 200 miles of bike trails around there. Like, these green things on the map, these are bike trails. And here's one of the trail which is next to my apartment, which is like so awesome. And actually, in Seattle, we can bike all year around because the weather is similar to London, and it doesn't rain that much. So it's just great. You know, before I lived in Kansas, and you know, in the winter, we had like minus 20 Celsius. So, you know, it wasn't possible. Here it is. Oh, and we have also one of the biggest bike rides in United States. It's called Seattle to Portland. And every year, 10,000 cyclists are going from Seattle to Portland to 200 miles in two days or one day. I did it for the first time last year. I did it in two days. This year, we have a plan with my friends to do it in one day. We'll see how this goes. And I know that we are in Europe now, and you're probably not big fans of American football. Actually, no, I don't know if I'm okay here, so I'm calling this football because it's rugby, right? But, you know, we have one of the best NFL teams in the U.S. Two years ago, we won the Super Bowl. Last year, we lost in like last minute, and we lost in a situation where in 999 out of 1,000 cases, we should have win. So, that was like, it was so bad. And this year, we are trying again. We just went through the first round of playoffs. We played with Minnesota Vikings. And actually, we should have lost because like the last minute, everything Vikings had to do, they had to just kick and score. And, you know, 9 times out of 10, the teams scored, and they missed. And that was so surprising that after the game, you know, I found this. I don't know if you guys have seen the Miss Universe, when the wrong lady got the crown, there was like music, and after that, they said, oh, I'm sorry, actually, it's not you. It's the other. So, this is Seahawks logo. This is Vikings. But let's go back to tech. So, this is Azure Data Center. Actually, I'm not sure if it really is, but I found it on Bink, so it should be. And this is Azure Coast in France. Actually, I was wondering what are the origins of the Azure name, where it's coming from. So, this is one of my ideas. It's pretty nice. I think this is Nice, or Nice. And the French people here, how to pronounce it? Nice. Nice. Okay. In English, it's Nice. And it's actually Nice, right? And I work on the project code name Ibiza, and this is actually Ibiza Island in Spain. You know, some people are wondering what is origin of this project, and some people said that, yeah, because after we shipped, we're supposed to go there for a party, but probably something didn't realize that our team can grow to such an extent that there will be like a couple hundred people at the time, and that might be an issue. But maybe we still will go sometime, I don't know. And the public name of the project I'm working on is the Microsoft Azure Management Portal. How many of you are using Azure? Okay. Almost most of the people here. Are you guys using the new portal? Who likes the new portal better than the old one? Who likes the old one more? Okay. Only two hands. All right. So, yeah, as you know, guys, I don't know if you figured this out, but if you double click on the dashboard, you can change the themes. I like this dark theme. We also have dark and blue theme. There's also light theme, which is pretty cool. I prefer the dark theme. And if you do F12, you can notice that we have the ASCII Arts in the console, and actually, as you might notice, there is even job offer in there. If you click this, it will go to Microsoft careers website. It will be job offered directly to our team. Because on Microsoft career, you can never figure out what the job offer is. You see something with algorithms, and you don't know it will be like Bing search engine, or maybe this will be some marketing website. But under this link, there are job offers directly to our team. So, if you're interested, click. So, a few things about the portal. For now, all people who contribute a code only to the front end of the portal, I'm not talking about the back and date PI to manage the Azure, but only to the front end of the portal is something around 500 people. I'm working in a team that builds the core of the portal, and the framework on top of other teams are building extensions. What we call extensions, for example, website extension, which adds functionality so you can manage your websites. There is also SQL extensions, you can manage your SQL. From your perspective, it's like you have websites and SQL, right? Because it looks like it's one piece, but underneath, they are like, they are separate. And as of today, you have 75 different extensions. When I started in this team over a year ago, we had maybe like 20, I don't know. So, you see, over the year, we grow so fast. And what we call blade is sort of the piece of the view with this play. So, if you open something on the portal, as you guys might notice, if you're using it, you get this separate view. You can consider it as Angular view, for example. And as of today, we have over 1800s of this view over there. And so the reason why we build a new portal, because a lot of people actually like the old one, but the problem with the old one was that it didn't scale, because it was a small application. When you wanted to release a new version, all teams had to sort of, you know, schedule and do the release together. And I'm talking here about only front end. Okay? Like back end services, they are independent still. But the front end growth as well, so then the front end even wasn't scaling. And the idea with the new portal, it was a little bit crazy. So we have this, well, this Azure website is the core of the portal. And on the Azure website, we expose the framework of the portal. And people who use, who build extensions like websites or SQL, what they have to do, they have to install our SDK that we provide to them. They say, they open Visual Studio, say file new project, Azure portal extension. And they have some sort of startup code. And they deploy their code independently. So their front end code is deployed independently. And then we only have the link to their end point on the portal. And we load their extensions. But what is good about that is that they can deploy whenever they want. We don't care. So if you are building websites extension, you can deploy even 4 a.m. And our team doesn't care about that. You can deploy 10 times per day or one time per month. Doesn't matter. The only thing that matters is you provide us this link to extension. And the extensions are actually separated from the core of the portal in such a way that every extension has a separate iframe. So we load only the JavaScript code in this iframe. And this extension works in such a way that in the portal we have some default settings file. And for example, we know, yeah, we want to load the website extension. We open website extension. And then we communicate with their iframe. And they do some computation, calling to the back end, and exchanging data with the portal. And the communication works through post messages. And this is also some sort of isolation thing in such a way that if, for example, some extension will have some error, the extension will crash, we are our JavaScript on the core of the portal will still work. And all other extensions will be fine. And actually, I can show you really quick if the internet will work. Go to the portal. And login, Microsoft.com. Okay, password. Okay, I need to factor off. So I'll get notification on my phone. Okay, got it. Okay, I'm in. So now the portal is loading. Let's see what happens. I'm really curious here. Because this is not website like all others. This is not just static content. Like there is a lot of requests happening now when this is loading. And you can actually consider this as sort of web virtual machine when the portal is like an operating system. And all the extensions are like separate applications built on top of it. And if you click the secret key combinations, control-ald-d, here, for example, you can see such a thing as the portal load time. So it loaded in four seconds. It's not that bad. And here you can see there is a list of extensions that were loaded initially. And we load extensions on demand. We don't load all 75 at the start because then we will have to load a lot of JavaScript. And we will kill your connection, especially if you don't have very good connection. What we load is Hubs extension. Hubs extension is actually some core extension of the portal that's without this portal will not work. The name of this extension is just from historical reasons. Here you can see we have cloud services. Here is their websites. There is SQL. And the extensions that are loaded here, they are loaded because we have tiles pinned to the dashboard. And you can see here, for example, here I have cloud services part. And again, part is historical reasons. We call this thing tiled and rename to part. And then again, rename to the tile now. Here we have some virtual machine and so on. And for example, for now, I don't have application insights. So if I click application insights, let me close this. I open some applications insights. Now the application insights extension should be loaded. And you can see here at the bottom, I also have this extension loaded. And then after extension is not anymore needed, we set, like if I close this, I think we set like 60-second polling. So we check, hey, is this extension still needed? And if it's not needed, we just unload this to don't have memory leaks and other performance issues. Because even without that, the portal is taking 230, it's 31. If you have opened it for a while, it goes to 300. Actually, it's much, much better now because there are times when it was over half gigabytes of memory needed to run this thing. So this is a quick overview of this stuff is built. And the technologies we are using, we are mainly using TypeScript because we are writing mainly front-end code. Of course, we have some ASP.net website in there, but this is like maybe fraction of the percentage of our code base. And TypeScript is actually very, very cool for that because we are building API that other people are consuming. And our framework team is over 50 developers working on one repo, one code base. And even communication in such a big group is hard. So when somebody is changing something and somebody else wants to use it, they don't know. And if we had JavaScript, we probably would have a lot of conflicting issues. In TypeScript, we have protection in strong typing. For those of you who are not familiar, TypeScript is a type superset of JavaScript. So it adds optional typing in top of JavaScript that prevents you from calling, for example, function wrong argument. Actually, let me show this really quick. So if I, let's say I have some function on the framework. So I have function, function, draw, or maybe display. And I have two params here. And let's say, you know, just for presentation purposes, I do a console look, displaying X and Y. Let's say minus 10. Let's assume this is doing something. And then, you know, this is on, you know, let's say this is function, it's on the, our framework level, let's say SDK framework. And then here, somebody who is writing extension, they are using this function. So they, for example, want to say display 10 and 20. And then I'll save this file. And this is in TypeScript. So I need to compile this to JavaScript. So I will say tscapi.ts. And now this will produce me the JavaScript file. And now I can run it with note. And now I can see I am displaying 0.10. Right? Here, actually, not much happened because the JavaScript code will look exactly like TypeScript because TypeScript is super set of JavaScript. So every valid JavaScript code is also valid TypeScript. But, you know, when, then we want to make some change. For example, somebody say, okay, I am providing numbers here, but what if, for example, I will say here 10X and 20Y, right? I mean, because why not? You can still compile this here because we don't have strong typing on the function hello. And if you run this, then doesn't look good, right? It is playing not a number, not a number. So you know what we do? We add typing, oops, we add typing to the parameters. So, for example, we can say here number and number. And now if somebody will try to compile this, they will get the compilation error. That you cannot pass this string to function that expects number. So then, you know, before you check in your code, you go back here and you are fixing this. And then it is 10. And here it will be 20. And then I can compile this. And then this will work. And this also is useful when, for example, you want to change the parameters. So for example, you want to say I don't want X and Y, maybe I just want to create some class because in TypeScript you can create some classes with X number property and Y number property. I can even create a constructor here. X and Y. I will not strongly type it for now. But I still can strongly type this as well. Say number and number here. And here I will just assign this X to this X and this Y to this Y. And, you know, this is all awesome. And now I don't want to pass X and Y anymore. I just want to pass the coordinates, which is Type X and Y, this class. And here I will just get these parameters from there. And then, of course, you have to change API. I am sure nobody is using it yet because I told them so, right? So for sure they are not using it because, you know, that's how it usually is, right? But then I compile and, oh, somebody didn't listen to me when I told them not to use it. They actually were using it. Okay. So they have to go back and they have to fix it. So they actually need to hear, go here and create new X and Y and say 10, 20. And then pass this C object here. Compile this one more time. And then when I run this, it works again, right? So this, you know, this TypeScript gives us sort of first unit tests, free unit tests, because, you know, sometimes I have seen somewhere, you know, in JavaScript unit tests, something like that, that looks, sorry, you have not equal and then you have some object, some function, and undefined. And I was like thinking, what is this? And so this is the way how in JavaScript you can make sure that somebody is not breaking some API or stuff like that. In TypeScript, you don't need this thing anymore. So that's our biggest thing that allows us to run this project. And another thing is a knockout.js library. We are using this to binding. We are not using any big framework like Angular or React. First, because we wanted to have flexibility. And the project also started three years ago when knockout was pretty mature, Angular, sort of starting. And what was also very convenient, the creator of knockout, Steve Sanderson was working with us. So either when we needed some features, we could just ask him. And they got like pretty high priority, which was pretty nice. And this library is also pretty good. We also use jQuery like everybody. We use required.js for asynchronous module loading. And this helps us a lot with performance. Because if we would like to load our entire JavaScript that we generate, it would be for now maybe like 20 megabytes. So we had to synchronously load. And for now, our start up code is like 1.5 megabytes or something like that because we crafted to get as low as possible in here. We also use d3. So if you see like the charts on the portal, which is like a lot, actually, on this what I showed you here, there's not many charts. But if you see here, for example, you have this monitoring. This is made with d3. It's pretty nice library. We also use HTML5. We use less, which helps to better maintain the CSS. We can write mixings and variables. For JavaScript or TypeScript testing, we use QUnit library. Why QUnit? Why not Jasmine? Because, again, the project started three years ago. At the time, QUnit was the most popular choice, but the best community support. We also use sign on JS for mocking in QUnit. And in the backend, in our website, we use C sharp. We have ASP.nvc, I think, four or four, NVC four, or maybe five. Not sure exactly about the version now. We also have one backend server in Node.js. This is actually pretty interesting because when we are in the portal and we have this iframes, like if you do f12 here, and if you go here, here you can see these are the extensions here. Here is the iframe, here is the hub extension, here is cloud services, the billing extension. And actually, you can even open this thing. So let's see. I open billing. I open linking you tap. So this is what we actually load to iframe. If you do control U, you see that here there is no UI. It's only JavaScript that, again, communicates with the website. And here, what is happening in this code is only some internal computation. We don't display anything here. So some people in our team figure out that, hey, when somebody has slow connection and the user does something and sometimes you need to do multiple calls to the server or get some multiple data to check something and you need to go back and forth, why we cannot run extension in the cloud. And then when you do request, it's fast because you are already there. You are not going anywhere. You have the fastest connection possible. And then we just set up the WebSocket connection between the website and this extension running in cloud. We call this relocatable extension. And this may be better for people who doesn't have the best Internet connection. And we are still experimenting with this, but in some cases it works. And this is pretty interesting, I think. For unit testing in C-Sharby's MS test, but most of our, we have some simple unit tests of the infrastructure and we even have some unit tests for the code size. So for example, if you are adding the code to our code base that will make the startup code bigger, you get a filing unit test. Which is, you know, somebody will say, oh, that doesn't make sense at all. But from the other hand, if you look at that, that you have more than 50 people working on one thing, like every person cannot know everything. Every person cannot know, like, is this file load at startup time or no? And if they get this filing test, they might be like, hey, actually, you know, maybe I can asynchronously load this, or maybe actually I have to do this and it's okay. You just fix the test, change the code size that is acceptable. Like, for example, one time, somebody needed to do some media player or something. And, you know, they first try was adding like two megabytes to startup code, right? Which is more than 100%. So then they got the filing test. But the most of our C sharp tests are Selenium tests, Selenium UI tests, and this is most of our C sharp code base. We also use Moku for mocking, but we have only a few tests using that, actually. And this is how our code base more or less looks like. You can sort of ignore the JavaScript because this is just compiled from TypeScript. So the actually code that we have written is here, like, it's around 800,000 lines of code. So we are going towards 1 million. And in C sharp, you can see that it's 240, but when I check how much our website has, our website has maybe something like 10,000. So it's only a fraction of this. Most of them are Selenium tests. Okay. So how we build this thing, how our development process looks like, I'm always interested how other people and other teams are doing that. So I'll tell you how we do it and maybe afterwards we can chat how you guys do it. So we use an environment called Core XT. This is a tool created at Microsoft. It's a little bit something like Vargon. These days, people use Vargon to create isolated dev environments. So you have the same environment for development like you have in the server. In Core XT is a little bit different. It is a set of PowerShell scripts and you get packages that by setting the environmental variables creates this environment that you can build from the code you have locally. You can build targeting the compiler that we are using in our build system and using the same version of.NET framework and so on. And then we write a code. Everybody loves to write a code. Actually, this is a meme called programming in the movies versus the real life. So this is real life and this is movies, right? That's what it looks like. That's what our families think we do, right? But actually, yeah, our life is boring. So in our case, we wouldn't be able to survive without unit tests. Like, seriously, maybe if you have a team of five or ten people, maybe, yeah, you can do a project without it. Like, for us, this is, like, not possible because almost every change you do, somehow there is some dependency somewhere there that you are breaking. You might not know, right? Because, of course, you cannot know everything. So in our always, when we commit some code, there has to be associated unit tests with it. And one problem with tests is that Selenium UI tests are pretty expensive because sometimes to run one test, it takes 30 seconds to even one minute to run the IIS, to log into the portal, do the authentication, all this stuff, and then you just click on one thing and, okay, it works. So we push towards using the Q unit tests in JavaScript, and we're trying to have more of them because in one minute you can run thousands of Q unit tests. And we also have TypeScript, which is our first very unit test, which is our, of course, biggest test base. And before we check in code, we commit code, we do code reviews. So in our team, the rule is that usually when you do some new functionality, you need to have a sign-off for two people. Usually the reason is, again, you might not know something, somebody might know some area or have some, you know, suggestion for you. And it's always when more people will look at some code piece and can give you some advice how to do stuff. Like sometimes if you are, like, you know, just fixing some CSS one pixel off, right? It's okay if just one person say okay. Or sometimes when it's something like really, really, really simple, then we somehow go without this. But usually we do code reviews. And, you know, it's not free because, you know, sometimes you get a code review, right? And you have 100 files changed, right? Please check if it's okay, right? Okay, cool. So this is what I will spend the whole my day today, right? So this is the problem. We are trying to do as small changes as possible. And just do code reviews that are as small as possible as well. Or, you know, if code review is big, we just do consultation on, or usually the people who are familiar with some area where we do changes are checking this. For our source control, we use Git, which is pretty cool. We always, yeah, you guys also really recommend always do private branches. Because, you know, if you don't save some work somewhere on the server, your machine can, you know, burn and your work will be wasted, right? So if you have your private branch, you can save a lot of work and, you know, commit as soon as possible. Like, you know, you can always amend the commit. So before you push it to repo, you can just say, you know, Git commit 1 to 3 and temporary have it and just push it to private branch. And once we push our code to code base, we develop a branch we call the dev branch. And after something goes to dev branch, we run the build in our build system. And then we run all our tests. We have a bunch of different tests. We have unit tests. We have the UI tests. We have some, for example, some sample extensions. We check if extension load works fine. And once everything goes through CI, continuous integration, and everything is green, no test failed. Then we merge everything to our branch that we call the doc food or RCE release candidate. And we run a release to our, we call it RC environment that is available there. And it's our first sort of continuous delivery stage. Because then later on, once code is there, we have also two other branches. One is called mpack, which stands for ms.portal.azure.com. And this is the place where all people from Microsoft, I think all MVPs are redirected when they go to portal.azure.com. And so they have the more fresh version, I would say. But we do this deployment manually. We used to do it every day. Now I think we do it once a week. We sort of still trying different approaches, trying to see what works the best. And the third branch here is called active, but we call it production. It's actually production branch. When we merge everything to production, we're on the build. We copy the bits to the cloud service and we do a release. We have, for now, we are geo replicated to all Azure regions. Actually, I'm still pretty scared when I'm doing this deployment, right? Because now you're releasing the thing that so many thousands of people are dependent on. And in our process, like, there is approval needed. So we have a group of people who are very experienced with deployment. They know all the stuff about this. So when somebody is trying to do deployment, they need to get sign off from some other person. So at least two person knows what is going on. And when something goes wrong at 4 a.m., two heads is always better than one. And this is our continuous integration board. So the first thing we do is build. And then we have, like, a bunch of different tests. So, for example, here you can see we rank unit testing Chrome. We also separate the around in IE. And here you can see this one is yellow because some tests failed probably there. So it's already beneficial. And we have some other tests. Like, for example, the compact tests, this is like sort of our contract with extension partners. We told them that, hey, you have three months backwards compatibility. Because at the beginning, the problem was that every time when we released the new SDK, they had to fix all the breaking changes we do. So now we told them, hey, we won't be doing breaking changes for three months. When we do breaking changes, we're just letting you know. And we will not obsolete the current API for three more months. But you should switch. You have, like, heads up. You will get a warning when you are developing. And you will know that you have to change. And we also have every week somebody is our CI board representative. So, you know, if somebody broke something, or sometimes it's like, because we don't have one CI run per commit, because we have almost 40 commits per day. And one full CI run takes almost like half an hour. So sometimes we have like three or four commits. And then something breaks. And then, of course, there are situations when all four people says, oh, for sure not me. For sure not me. So then we have this guy that he's sort of like figuring out who broke. Maybe there is some issue with continuous regression infrastructure. Because, you know, we run our tests actually in the cloud. And we run them in parallel. In bugging days, we had issues with Flaky tests. Because sometimes, you know, for example, you just lose connection to virtual machine or something during the virtual machine setup went wrong. And sometimes it was marked as failed. And, you know, all CI was green. What we do now, when some tests fail, we do a retry two times. And if you know that two consecutive tries are passing, we say, okay, so this test actually is just Flaky. It's okay. Something just went wrong on CI. And if somebody breaks the build, he got the unique error on his desk. And a couple of random things we do. I don't know. How many of you guys are web developers? Okay. So almost like everybody in the room. Probably you also have this pain like every web developer with back supporting the old browsers, right? And unfortunately, some of you might, for example, building the current system when the gentleman who is retired from Kentucky, and he has his laptop running Windows XP and then, for example, IE6, he wants to rent a car. So you better support this because he probably has a lot of money you can make on him, right? We are actually fortunate enough that we don't have to do this because our customers are developers. So they usually are up to date with stuff. So we just support the latest versions of all new browsers. Also only the latest version of IE, which is IE11 at this point. When I say we don't support lower versions, it doesn't mean it will not work there. It will be just if we get some bug that only reproves in, let's say, IE8 or IE9, we will not spend time on fixing it because it's just not very efficient. Like for now, the biggest pain for us is Safari. We actually support Safari only on Mac, only the latest version, but there are still a lot of weird issues. I'm not sure why. Like, for example, Safari is the only browser out of these that doesn't support internationalization's API called Intel. Like, Safari doesn't have this. Yeah, we had to polyfill, and this is actually pretty expensive because to polyfill one culture specific region is, I think, like 50 kilobytes. So if you want to polyfill 20 or 30, you need to load a lot of code into the browser, you need to download all of this. It should be made by browser. Also, many times we get some weird Safari bugs. And recently I've seen an article that says, Safari is a new IE, whatever that means. And as I said, when we don't test, it doesn't mean it doesn't work somewhere. So this is my friend's Tesla car, and we run the portal there and it loaded. But I'm not sure if it still works because that was like over half a year ago, I think. I'm not sure if it still works because, again, we don't run our tests in Tesla. But yeah, the same is with the phones, for example. You might try to use it. It's hard. You might be lucky. You might be not if you have some weird old Nokia phone. It might not really work. And the last and the biggest piece we do at the end of our sort of development, because the new portal became version one in December last year, so like a month ago. At Microsoft, we call it GA, general availability. Rest of the world say just V1. You're not beta anymore. You are V1. And we are beta for almost year and a half, if I remember correctly. There are like multiple reasons. One of the reasons was fast growth of Azure. We have more and more people who wants to put stuff in and they're putting in the old portal because, you know, this is what everybody was using. They didn't have enough time to put it in the new one, so on and so forth. And, you know, at the beginning, I got to know if you guys try to use portal over a year ago, but it was super slow. Like you could, if you have the newest machine, it was hard to use it. Earlier last year, it was getting better and better because, you know, we left the performance at the end, right? Because first you need to get stuff working. And because of many, you know, architectural choices and many reasons, like it was even hard to get the basics, to get the old extension running, to get all the features for extension they needed because, you know, some extensions, they have some very specific things that we had to support and so on. So the last run before becoming V1 was the work on the performance. And one of the things was, for example, the extension reliability. So, as I told you, we load extensions sort of on demand. We are saying, hey, please load this extension. And, you know, when you do a lot of requests and especially if you have not the best connection, you can just get time out, right? And then, you know, this extension is not loading and stuff is not working. And if you load, like, five or six extensions, it's pretty likely that maybe one of 100 requests, maybe one of them will not fully load at some point sometime, right? So then our goal was to have 99.9%. So that means we have only one failure per 1000 requests to that. And how we ensure that we did the retry logic. So if extension failed to load, we try again. And we have time out set to, I'm not sure if it's 60 or 90 seconds. But we retry two times. And if after two times it doesn't load, then we market as failure. And before becoming V1, our goal was to do this 99.9%. And now we are above that. Another thing was the code size reduced. As I mentioned, our code base is huge. You have seen almost one million of TypeScript code lines. So there are a few people who are working on this, how they can, you know, resolve dependencies in such a way that the minimal amount of code will be loaded at the start-up. And also how to make this code as small as possible. And for example, one of the ideas was in JavaScript is to capture the calling, you know, nesting variables. So even if you use minifier, minifier not always can do all the work for you. Like, for example, if you open them here, so for example, if you have something and you call some object and some property of this object and some other property and something else, if these properties are public, usually minifier cannot really minify because, you know, they don't know what will happen, right? And if you call it once, it's fine. But then later on, you do again some property of this object, other property, something else, and you do it like a few times in your code. It's not minified. But if you capture, for example, let's say here, I am just saying, here I am saying this, you know, blah, blah, blah, blah, blah, blah. So I am actually using the same thing in here. Sorry. So actually, I am using the same thing all over here, right? I am accessing different objects here, right? So if you go to the top of the file and you say let other this or whatever, and you call it property of this object, other property, and then here you can just say other this and you can say the same here. So let me do it. I can say, oops, sorry, oops, other this and one and boom, boom, boom, oops, sorry. What do I mean? Yep. And three, two, 12, 11. And if you have this code and then you want to minify this, then your minifier will produce code that looks more like that. Again, this cannot be here. This cannot be minified here. But this here probably will be like A, X, B, X, C, and so on, right? So here you can, you know, per line you can say like 10 or 20 bytes. So if you are calling it 10 times, you have like 100 bytes and then if you spread it over a few files, you can save 10, 20, maybe 30, maybe 300 kilobytes and then this matters. So it's like, you know, very small thing, but at the end, if you add everything, it matters. And so it sounds crazy, right? You just captured the naming of objects, but it worked. Another thing, as I mentioned, we do lazy loading of our components. So for example, one part of the framework is controls. So we deliver the universal controls for the users. So you know, if you are in the portal and you see, for example, this, you see this is Textbox. This is not created by this particular extension partner. This is created by us framework. And they just reuse our control and they just communicate with the view model and getting the value and we provide the validation and all the support for them. And we don't want to load all controls at the start because, again, the control code base is also big. So we just load control when it's needed. So when it's displayed, we asynchronously loaded them. And now we are also starting working on the lazy loading of our styles because our CSS are also pretty big. And you might say it won't matter. But then again, if you have a big code base, you have 50 developers adding code every day. After some time, it grows to such an extent that it's hard to control and then it actually matters in the slow connections. And this is actually the speaker is from my co-worker blog. So what we have to do and all of you have to do as well, when the number of users of your website is growing, the number of features of your website is growing, you need to keep the page load time constant. And this is very challenging because you have bigger load, but you still need to be there. Because it's like, actually it makes sense, right? You have more users, you'll be slower, right? But we cannot really do that. We need to go down instead of going up in here. And you know how to do this? So in this, you know, simple algorithm here, right? We just measure different parameters and figure out maybe this will do. We do this change, then measure again. Is it better? Is it improved? If no, then try different things. And if it is, then we measure some other things and we come up with other ideas, how we can do stuff. And that's how we come up with idea of the relocatable extensions that we run the client, actually, clients at JavaScript on the server. And actually, tomorrow there is Steve Sanderson talk. He is now working on running front-end JavaScript on the back-end with ASP.NET. So I believe his work now was a little bit inspired by the work we are doing in the portal. So this is pretty much all I have. So thank you very much. And please find me after my session. I will be happy to talk to you. Thank you.
 Thank you.  Thank you.  Good afternoon. Thanks for coming for my session.  So my name is Jacob. And I work for Microsoft.  And you can find more information about myself at my  blog at JJ09.net. I encourage you to subscribe even if you  would like to.  I came here for the nicest city in the world in Seattle, in  United States. It's really gorgeous there.  Anybody here have been in Seattle, maybe?  How did you like it?  Okay. Just for recording purposes, like, entire audience  say they like it.  Actually, I live in the city of Redmond, and I'm a cyclist.  And before I moved to Redmond, I didn't know that Redmond is  like the best place on earth for cyclists.  We have over 200 miles of bike trails around there.  Like, these green things on the map, these are bike trails.  And here's one of the trail which is next to my apartment,  which is like so awesome. And actually, in Seattle, we can  bike all year around because the weather is similar to London,  and it doesn't rain that much. So it's just great.  You know, before I lived in Kansas, and you know, in the  winter, we had like minus 20 Celsius.  So, you know, it wasn't possible. Here it is.  Oh, and we have also one of the biggest bike rides in  United States. It's called Seattle to Portland.  And every year, 10,000 cyclists are going from Seattle to  Portland to 200 miles in two days or one day.  I did it for the first time last year. I did it in two days.  This year, we have a plan with my friends to do it in one day.  We'll see how this goes.  And I know that we are in Europe now, and you're probably  not big fans of American football. Actually, no, I don't  know if I'm okay here, so I'm calling this football because  it's rugby, right?  But, you know, we have one of the best NFL teams in  the U.S. Two years ago, we won the Super Bowl.  Last year, we lost in like last minute, and we lost in a  situation where in 999 out of 1,000 cases, we should have  win. So, that was like, it was so bad.  And this year, we are trying again. We just went through  the first round of playoffs. We played with Minnesota Vikings.  And actually, we should have lost because like the last  minute, everything Vikings had to do, they had to just  kick and score. And, you know, 9 times out of 10, the teams  scored, and they missed. And that was so surprising that  after the game, you know, I found this. I don't know if you  guys have seen the Miss Universe, when the wrong lady got  the crown, there was like music, and after that, they said,  oh, I'm sorry, actually, it's not you. It's the other.  So, this is Seahawks logo. This is Vikings.  But let's go back to tech. So, this is Azure Data Center.  Actually, I'm not sure if it really is, but I found it on  Bink, so it should be.  And this is Azure Coast in France. Actually, I was wondering  what are the origins of the Azure name, where it's coming  from. So, this is one of my ideas. It's pretty nice. I think  this is Nice, or Nice. And the French people here, how to  pronounce it? Nice. Nice. Okay. In English, it's Nice. And  it's actually Nice, right? And I work on the project code  name Ibiza, and this is actually Ibiza Island in Spain. You  know, some people are wondering what is origin of this  project, and some people said that, yeah, because after we  shipped, we're supposed to go there for a party, but probably  something didn't realize that our team can grow to such an  extent that there will be like a couple hundred people at the  time, and that might be an issue. But maybe we still will go  sometime, I don't know. And the public name of the project  I'm working on is the Microsoft Azure Management Portal. How  many of you are using Azure? Okay. Almost most of the people  here. Are you guys using the new portal? Who likes the new  portal better than the old one? Who likes the old one more?  Okay. Only two hands. All right. So, yeah, as you know, guys,  I don't know if you figured this out, but if you double click  on the dashboard, you can change the themes. I like this dark  theme. We also have dark and blue theme. There's also light  theme, which is pretty cool. I prefer the dark theme. And if you  do F12, you can notice that we have the ASCII Arts in the  console, and actually, as you might notice, there is even  job offer in there. If you click this, it will go to  Microsoft careers website. It will be job offered directly to  our team. Because on Microsoft career, you can never figure  out what the job offer is. You see something with algorithms,  and you don't know it will be like Bing search engine, or  maybe this will be some marketing website. But under this  link, there are job offers directly to our team. So, if  you're interested, click. So, a few things about the portal.  For now, all people who contribute a code only to the  front end of the portal, I'm not talking about the back and  date PI to manage the Azure, but only to the front end of the  portal is something around 500 people. I'm working in a team  that builds the core of the portal, and the framework on top  of other teams are building extensions. What we call  extensions, for example, website extension, which adds  functionality so you can manage your websites. There is also  SQL extensions, you can manage your SQL. From your  perspective, it's like you have websites and SQL, right?  Because it looks like it's one piece, but underneath, they  are like, they are separate. And as of today, you have 75  different extensions. When I started in this team over a year  ago, we had maybe like 20, I don't know. So, you see, over  the year, we grow so fast. And what we call blade is sort of  the piece of the view with this play. So, if you open something  on the portal, as you guys might notice, if you're using it,  you get this separate view. You can consider it as Angular  view, for example. And as of today, we have over 1800s of  this view over there. And so the reason why we build a new  portal, because a lot of people actually like the old one, but  the problem with the old one was that it didn't scale, because  it was a small application. When you wanted to release a new  version, all teams had to sort of, you know, schedule and do  the release together. And I'm talking here about only front  end. Okay? Like back end services, they are independent  still. But the front end growth as well, so then the front end  even wasn't scaling. And the idea with the new portal, it was  a little bit crazy. So we have this, well, this Azure website  is the core of the portal. And on the Azure website, we  expose the framework of the portal. And people who use, who  build extensions like websites or SQL, what they have to do, they  have to install our SDK that we provide to them. They say, they  open Visual Studio, say file new project, Azure portal extension.  And they have some sort of startup code. And they deploy their  code independently. So their front end code is deployed  independently. And then we only have the link to their end  point on the portal. And we load their extensions. But what is  good about that is that they can deploy whenever they want. We  don't care. So if you are building websites extension, you  can deploy even 4 a.m. And our team doesn't care about that. You  can deploy 10 times per day or one time per month. Doesn't  matter. The only thing that matters is you provide us this  link to extension. And the extensions are actually separated  from the core of the portal in such a way that every extension  has a separate iframe. So we load only the JavaScript code in  this iframe. And this extension works in such a way that in the  portal we have some default settings file. And for example,  we know, yeah, we want to load the website extension. We open  website extension. And then we communicate with their iframe.  And they do some computation, calling to the back end, and  exchanging data with the portal. And the communication works  through post messages. And this is also some sort of  isolation thing in such a way that if, for example, some extension  will have some error, the extension will crash, we are our  JavaScript on the core of the portal will still work. And all  other extensions will be fine. And actually, I can show you  really quick if the internet will work. Go to the portal.  And login, Microsoft.com. Okay, password. Okay, I need  to factor off. So I'll get notification on my phone. Okay, got it.  Okay, I'm in. So now the portal is loading. Let's see what  happens. I'm really curious here. Because this is not  website like all others. This is not just static content. Like  there is a lot of requests happening now when this is  loading. And you can actually consider this as sort of web  virtual machine when the portal is like an operating system. And  all the extensions are like separate applications built on  top of it. And if you click the secret key combinations,  control-ald-d, here, for example, you can see such a thing as  the portal load time. So it loaded in four seconds. It's not  that bad. And here you can see there is a list of extensions  that were loaded initially. And we load extensions on demand.  We don't load all 75 at the start because then we will have  to load a lot of JavaScript. And we will kill your connection,  especially if you don't have very good connection. What we load  is Hubs extension. Hubs extension is actually some core  extension of the portal that's without this portal will not  work. The name of this extension is just from historical  reasons. Here you can see we have cloud services. Here is  their websites. There is SQL. And the extensions that are  loaded here, they are loaded because we have tiles pinned to  the dashboard. And you can see here, for example, here I have  cloud services part. And again, part is historical reasons. We  call this thing tiled and rename to part. And then again, rename  to the tile now. Here we have some virtual machine and so on.  And for example, for now, I don't have application  insights. So if I click application insights, let me  close this. I open some applications insights. Now the  application insights extension should be loaded. And you can  see here at the bottom, I also have this extension loaded. And  then after extension is not anymore needed, we set, like if  I close this, I think we set like 60-second polling. So we  check, hey, is this extension still needed? And if it's not  needed, we just unload this to don't have memory leaks and  other performance issues. Because even without that, the  portal is taking 230, it's 31. If you have opened it for a while,  it goes to 300. Actually, it's much, much better now because  there are times when it was over half gigabytes of memory  needed to run this thing. So this is a quick overview of this  stuff is built. And the technologies we are using, we are  mainly using TypeScript because we are writing mainly front-end  code. Of course, we have some ASP.net website in there, but  this is like maybe fraction of the percentage of our code base.  And TypeScript is actually very, very cool for that because we  are building API that other people are consuming. And our  framework team is over 50 developers working on one repo, one  code base. And even communication in such a big group is hard.  So when somebody is changing something and somebody else  wants to use it, they don't know. And if we had JavaScript, we  probably would have a lot of conflicting issues. In TypeScript,  we have protection in strong typing. For those of you who are  not familiar, TypeScript is a type superset of JavaScript. So it  adds optional typing in top of JavaScript that prevents you from  calling, for example, function wrong argument. Actually, let  me show this really quick. So if I, let's say I have some  function on the framework. So I have function,  function, draw, or maybe display. And I have two params here.  And let's say, you know, just for presentation purposes, I do  a console look, displaying X and Y. Let's say minus 10. Let's  assume this is doing something. And then, you know, this is on,  you know, let's say this is function, it's on the, our framework  level, let's say SDK framework. And then here, somebody who is  writing extension, they are using this function. So they, for  example, want to say display 10 and 20. And then I'll save this  file. And this is in TypeScript. So I need to compile this to  JavaScript. So I will say tscapi.ts. And now this will produce  me the JavaScript file. And now I can run it with note. And now  I can see I am displaying 0.10. Right? Here, actually, not much  happened because the JavaScript code will look exactly like  TypeScript because TypeScript is super set of JavaScript. So  every valid JavaScript code is also valid TypeScript. But, you  know, when, then we want to make some change. For example,  somebody say, okay, I am providing numbers here, but what if,  for example, I will say here 10X and 20Y, right? I mean, because  why not? You can still compile this here because we don't have  strong typing on the function hello. And if you run this, then  doesn't look good, right? It is playing not a number, not a  number. So you know what we do? We add typing, oops, we add  typing to the parameters. So, for example, we can say here  number and number. And now if somebody will try to compile this,  they will get the compilation error. That you cannot pass this  string to function that expects number. So then, you know,  before you check in your code, you go back here and you are  fixing this. And then it is 10. And here it will be 20. And then  I can compile this. And then this will work. And this also is  useful when, for example, you want to change the parameters. So  for example, you want to say I don't want X and Y, maybe I just  want to create some class because in TypeScript you can create  some classes with X number property and Y number property. I  can even create a constructor here. X and Y. I will not  strongly type it for now. But I still can strongly type this  as well. Say number and number here. And here I will just  assign this X to this X and this Y to this Y. And, you know, this  is all awesome. And now I don't want to pass X and Y anymore. I  just want to pass the coordinates, which is Type X and Y, this  class. And here I will just get these parameters from there. And  then, of course, you have to change API. I am sure nobody is  using it yet because I told them so, right? So for sure they  are not using it because, you know, that's how it usually is,  right? But then I compile and, oh, somebody didn't listen to me  when I told them not to use it. They actually were using it.  Okay. So they have to go back and they have to fix it. So they  actually need to hear, go here and create new X and Y and say  10, 20. And then pass this C object here. Compile this one more  time. And then when I run this, it works again, right? So this,  you know, this TypeScript gives us sort of first unit tests,  free unit tests, because, you know, sometimes I have seen  somewhere, you know, in JavaScript unit tests, something  like that, that looks, sorry, you have not equal and then you  have some object, some function, and undefined. And I was like  thinking, what is this? And so this is the way how in JavaScript  you can make sure that somebody is not breaking some API or  stuff like that. In TypeScript, you don't need this thing  anymore. So that's our biggest thing that allows us to run this  project. And another thing is a knockout.js library. We are  using this to binding. We are not using any big framework like  Angular or React. First, because we wanted to have flexibility.  And the project also started three years ago when knockout was  pretty mature, Angular, sort of starting. And what was also  very convenient, the creator of knockout, Steve Sanderson was  working with us. So either when we needed some features, we  could just ask him. And they got like pretty high priority, which  was pretty nice. And this library is also pretty good. We  also use jQuery like everybody. We use required.js for  asynchronous module loading. And this helps us a lot with  performance. Because if we would like to load our entire  JavaScript that we generate, it would be for now maybe like 20  megabytes. So we had to synchronously load. And for now, our  start up code is like 1.5 megabytes or something like that  because we crafted to get as low as possible in here. We also  use d3. So if you see like the charts on the portal, which is  like a lot, actually, on this what I showed you here, there's  not many charts. But if you see here, for example, you have  this monitoring. This is made with d3. It's pretty nice  library. We also use HTML5. We use less, which helps to better  maintain the CSS. We can write mixings and variables. For  JavaScript or TypeScript testing, we use QUnit library. Why  QUnit? Why not Jasmine? Because, again, the project started  three years ago. At the time, QUnit was the most popular  choice, but the best community support. We also use sign on  JS for mocking in QUnit. And in the backend, in our website, we  use C sharp. We have ASP.nvc, I think, four or four, NVC four,  or maybe five. Not sure exactly about the version now. We also  have one backend server in Node.js. This is actually pretty  interesting because when we are in the portal and we have this  iframes, like if you do f12 here, and if you go here, here you  can see these are the extensions here. Here is the iframe, here  is the hub extension, here is cloud services, the billing  extension. And actually, you can even open this thing. So let's  see. I open billing. I open linking you tap. So this is what  we actually load to iframe. If you do control U, you see that  here there is no UI. It's only JavaScript that, again,  communicates with the website. And here, what is happening in  this code is only some internal computation. We don't display  anything here. So some people in our team figure out that, hey,  when somebody has slow connection and the user does  something and sometimes you need to do multiple calls to the  server or get some multiple data to check something and you  need to go back and forth, why we cannot run extension in the  cloud. And then when you do request, it's fast because you  are already there. You are not going anywhere. You have the  fastest connection possible. And then we just set up the  WebSocket connection between the website and this extension  running in cloud. We call this relocatable extension. And this  may be better for people who doesn't have the best Internet  connection. And we are still experimenting with this, but in  some cases it works. And this is pretty interesting, I think.  For unit testing in C-Sharby's MS test, but most of our, we  have some simple unit tests of the infrastructure and we even  have some unit tests for the code size. So for example, if you  are adding the code to our code base that will make the  startup code bigger, you get a filing unit test. Which is, you  know, somebody will say, oh, that doesn't make sense at all.  But from the other hand, if you look at that, that you have  more than 50 people working on one thing, like every person  cannot know everything. Every person cannot know, like, is this  file load at startup time or no? And if they get this filing  test, they might be like, hey, actually, you know, maybe I can  asynchronously load this, or maybe actually I have to do this  and it's okay. You just fix the test, change the code size  that is acceptable. Like, for example, one time, somebody  needed to do some media player or something. And, you know, they  first try was adding like two megabytes to startup code, right?  Which is more than 100%. So then they got the filing test.  But the most of our C sharp tests are Selenium tests, Selenium  UI tests, and this is most of our C sharp code base. We also  use Moku for mocking, but we have only a few tests using  that, actually. And this is how our code base more or less  looks like. You can sort of ignore the JavaScript because  this is just compiled from TypeScript. So the actually code  that we have written is here, like, it's around 800,000 lines  of code. So we are going towards 1 million. And in C sharp,  you can see that it's 240, but when I check how much our  website has, our website has maybe something like 10,000.  So it's only a fraction of this. Most of them are Selenium  tests. Okay. So how we build this thing, how our development  process looks like, I'm always interested how other people and  other teams are doing that. So I'll tell you how we do it and  maybe afterwards we can chat how you guys do it. So we use  an environment called Core XT. This is a tool created at  Microsoft. It's a little bit something like Vargon. These  days, people use Vargon to create isolated dev environments.  So you have the same environment for development like you have  in the server. In Core XT is a little bit different. It is a  set of PowerShell scripts and you get packages that by setting  the environmental variables creates this environment that you  can build from the code you have locally. You can build  targeting the compiler that we are using in our build system and  using the same version of.NET framework and so on. And then  we write a code. Everybody loves to write a code. Actually,  this is a meme called programming in the movies versus the real  life. So this is real life and this is movies, right? That's  what it looks like. That's what our families think we do, right?  But actually, yeah, our life is boring. So in our case, we  wouldn't be able to survive without unit tests. Like, seriously,  maybe if you have a team of five or ten people, maybe, yeah, you  can do a project without it. Like, for us, this is, like, not  possible because almost every change you do, somehow there is  some dependency somewhere there that you are breaking. You  might not know, right? Because, of course, you cannot know  everything. So in our always, when we commit some code, there  has to be associated unit tests with it. And one problem with  tests is that Selenium UI tests are pretty expensive because  sometimes to run one test, it takes 30 seconds to even one  minute to run the IIS, to log into the portal, do the  authentication, all this stuff, and then you just click on one  thing and, okay, it works. So we push towards using the Q  unit tests in JavaScript, and we're trying to have more of  them because in one minute you can run thousands of Q  unit tests. And we also have TypeScript, which is our first  very unit test, which is our, of course, biggest test base.  And before we check in code, we commit code, we do code  reviews. So in our team, the rule is that usually when you do  some new functionality, you need to have a sign-off for two  people. Usually the reason is, again, you might not know  something, somebody might know some area or have some, you  know, suggestion for you. And it's always when more people will  look at some code piece and can give you some advice how to do  stuff. Like sometimes if you are, like, you know, just fixing  some CSS one pixel off, right? It's okay if just one person  say okay. Or sometimes when it's something like really, really,  really simple, then we somehow go without this. But usually we  do code reviews. And, you know, it's not free because, you  know, sometimes you get a code review, right? And you have  100 files changed, right? Please check if it's okay, right?  Okay, cool. So this is what I will spend the whole my day  today, right? So this is the problem. We are trying to do  as small changes as possible. And just do code reviews that are  as small as possible as well. Or, you know, if code review is  big, we just do consultation on, or usually the people who are  familiar with some area where we do changes are checking this.  For our source control, we use Git, which is pretty cool. We  always, yeah, you guys also really recommend always do  private branches. Because, you know, if you don't save some  work somewhere on the server, your machine can, you know, burn  and your work will be wasted, right? So if you have your private  branch, you can save a lot of work and, you know, commit as  soon as possible. Like, you know, you can always amend the  commit. So before you push it to repo, you can just say, you  know, Git commit 1 to 3 and temporary have it and just push  it to private branch. And once we push our code to code base,  we develop a branch we call the dev branch. And after  something goes to dev branch, we run the build in our build  system. And then we run all our tests. We have a bunch of  different tests. We have unit tests. We have the UI tests. We  have some, for example, some sample extensions. We check if  extension load works fine. And once everything goes through  CI, continuous integration, and everything is green, no test  failed. Then we merge everything to our branch that we  call the doc food or RCE release candidate. And we run a  release to our, we call it RC environment that is available  there. And it's our first sort of continuous delivery stage.  Because then later on, once code is there, we have also two  other branches. One is called mpack, which stands for ms.portal.azure.com.  And this is the place where all people from Microsoft, I think  all MVPs are redirected when they go to portal.azure.com. And  so they have the more fresh version, I would say. But we do  this deployment manually. We used to do it every day. Now I  think we do it once a week. We sort of still trying different  approaches, trying to see what works the best. And the third  branch here is called active, but we call it production. It's  actually production branch. When we merge everything to  production, we're on the build. We copy the bits to the cloud  service and we do a release. We have, for now, we are geo  replicated to all Azure regions. Actually, I'm still pretty  scared when I'm doing this deployment, right? Because now  you're releasing the thing that so many thousands of people  are dependent on. And in our process, like, there is approval  needed. So we have a group of people who are very experienced  with deployment. They know all the stuff about this. So when  somebody is trying to do deployment, they need to get  sign off from some other person. So at least two person knows  what is going on. And when something goes wrong at 4 a.m.,  two heads is always better than one. And this is our  continuous integration board. So the first thing we do is  build. And then we have, like, a bunch of different tests.  So, for example, here you can see we rank unit testing Chrome.  We also separate the around in IE. And here you can see this  one is yellow because some tests failed probably there. So  it's already beneficial. And we have some other tests. Like,  for example, the compact tests, this is like sort of our  contract with extension partners. We told them that, hey, you  have three months backwards compatibility. Because at the  beginning, the problem was that every time when we released the  new SDK, they had to fix all the breaking changes we do. So now  we told them, hey, we won't be doing breaking changes for  three months. When we do breaking changes, we're just letting  you know. And we will not obsolete the current API for  three more months. But you should switch. You have, like,  heads up. You will get a warning when you are developing.  And you will know that you have to change. And we also have  every week somebody is our CI board representative. So, you  know, if somebody broke something, or sometimes it's  like, because we don't have one CI run per commit, because we  have almost 40 commits per day. And one full CI run takes  almost like half an hour. So sometimes we have like three or  four commits. And then something breaks. And then, of course,  there are situations when all four people says, oh, for sure  not me. For sure not me. So then we have this guy that he's  sort of like figuring out who broke. Maybe there is some issue  with continuous regression infrastructure. Because, you know,  we run our tests actually in the cloud. And we run them in  parallel. In bugging days, we had issues with Flaky tests.  Because sometimes, you know, for example, you just lose  connection to virtual machine or something during the virtual  machine setup went wrong. And sometimes it was marked as  failed. And, you know, all CI was green. What we do now, when  some tests fail, we do a retry two times. And if you know that  two consecutive tries are passing, we say, okay, so this test  actually is just Flaky. It's okay. Something just went wrong  on CI. And if somebody breaks the build, he got the unique  error on his desk. And a couple of random things we do. I  don't know. How many of you guys are web developers? Okay. So  almost like everybody in the room. Probably you also have this  pain like every web developer with back supporting the old  browsers, right? And unfortunately, some of you might, for  example, building the current system when the gentleman who is  retired from Kentucky, and he has his laptop running Windows  XP and then, for example, IE6, he wants to rent a car. So you  better support this because he probably has a lot of money you  can make on him, right? We are actually fortunate enough that  we don't have to do this because our customers are developers.  So they usually are up to date with stuff. So we just support  the latest versions of all new browsers. Also only the latest  version of IE, which is IE11 at this point. When I say we don't  support lower versions, it doesn't mean it will not work  there. It will be just if we get some bug that only reproves in,  let's say, IE8 or IE9, we will not spend time on fixing it  because it's just not very efficient. Like for now, the  biggest pain for us is Safari. We actually support Safari only  on Mac, only the latest version, but there are still a lot of  weird issues. I'm not sure why. Like, for example, Safari is the  only browser out of these that doesn't support internationalization's  API called Intel. Like, Safari doesn't have this. Yeah, we had  to polyfill, and this is actually pretty expensive because to  polyfill one culture specific region is, I think, like 50  kilobytes. So if you want to polyfill 20 or 30, you need to  load a lot of code into the browser, you need to download all  of this. It should be made by browser. Also, many times we get  some weird Safari bugs. And recently I've seen an article that  says, Safari is a new IE, whatever that means. And as I said,  when we don't test, it doesn't mean it doesn't work somewhere. So  this is my friend's Tesla car, and we run the portal there and  it loaded. But I'm not sure if it still works because that was  like over half a year ago, I think. I'm not sure if it still  works because, again, we don't run our tests in Tesla. But  yeah, the same is with the phones, for example. You might try  to use it. It's hard. You might be lucky. You might be not if you  have some weird old Nokia phone. It might not really work. And  the last and the biggest piece we do at the end of our sort of  development, because the new portal became version one in  December last year, so like a month ago. At Microsoft, we call  it GA, general availability. Rest of the world say just V1.  You're not beta anymore. You are V1. And we are beta for almost  year and a half, if I remember correctly. There are like multiple  reasons. One of the reasons was fast growth of Azure. We have  more and more people who wants to put stuff in and they're putting  in the old portal because, you know, this is what everybody was  using. They didn't have enough time to put it in the new one,  so on and so forth. And, you know, at the beginning, I got to  know if you guys try to use portal over a year ago, but it was  super slow. Like you could, if you have the newest machine, it  was hard to use it. Earlier last year, it was getting better and  better because, you know, we left the performance at the end,  right? Because first you need to get stuff working. And because  of many, you know, architectural choices and many reasons, like  it was even hard to get the basics, to get the old extension  running, to get all the features for extension they needed  because, you know, some extensions, they have some very  specific things that we had to support and so on. So the last  run before becoming V1 was the work on the performance. And one  of the things was, for example, the extension reliability. So,  as I told you, we load extensions sort of on demand. We are  saying, hey, please load this extension. And, you know, when you  do a lot of requests and especially if you have not the  best connection, you can just get time out, right? And then, you  know, this extension is not loading and stuff is not working.  And if you load, like, five or six extensions, it's pretty  likely that maybe one of 100 requests, maybe one of them will  not fully load at some point sometime, right? So then our goal  was to have 99.9%. So that means we have only one  failure per 1000 requests to that. And how we ensure that we  did the retry logic. So if extension failed to load, we try  again. And we have time out set to, I'm not sure if it's 60 or  90 seconds. But we retry two times. And if after two times  it doesn't load, then we market as failure. And before becoming  V1, our goal was to do this 99.9%. And now we are above that.  Another thing was the code size reduced. As I mentioned, our  code base is huge. You have seen almost one million of  TypeScript code lines. So there are a few people who are  working on this, how they can, you know, resolve dependencies  in such a way that the minimal amount of code will be loaded  at the start-up. And also how to make this code as  small as possible. And for example, one of the ideas was in  JavaScript is to capture the calling, you know, nesting  variables. So even if you use minifier, minifier not always  can do all the work for you. Like, for example, if you open  them here, so for example, if you have something and you call  some object and some property of this object and some other  property and something else, if these properties are public,  usually minifier cannot really minify because, you know, they  don't know what will happen, right? And if you call it once,  it's fine. But then later on, you do again some property of  this object, other property, something else, and you do it  like a few times in your code. It's not minified. But if you  capture, for example, let's say here, I am just saying, here  I am saying this, you know, blah, blah, blah, blah, blah, blah.  So I am actually using the same thing in here. Sorry. So  actually, I am using the same thing all over here, right? I  am accessing different objects here, right? So if you go to the  top of the file and you say let other this or whatever, and  you call it property of this object, other property, and then  here you can just say other this and you can say the same  here. So let me do it. I can say, oops, sorry, oops, other this  and one and boom, boom, boom, oops, sorry. What do I mean?  Yep. And three, two, 12, 11. And if you have this code and  then you want to minify this, then your minifier will produce  code that looks more like that. Again, this cannot be here.  This cannot be minified here. But this here probably will be  like A, X, B, X, C, and so on, right? So here you can, you  know, per line you can say like 10 or 20 bytes. So if you are  calling it 10 times, you have like 100 bytes and then if you  spread it over a few files, you can save 10, 20, maybe 30,  maybe 300 kilobytes and then this matters. So it's like, you  know, very small thing, but at the end, if you add everything,  it matters. And so it sounds crazy, right? You just captured  the naming of objects, but it worked. Another thing, as I  mentioned, we do lazy loading of our components. So for example,  one part of the framework is controls. So we deliver the  universal controls for the users. So you know, if you are in  the portal and you see, for example, this, you see this is  Textbox. This is not created by this particular extension  partner. This is created by us framework. And they just reuse  our control and they just communicate with the view  model and getting the value and we provide the validation and  all the support for them. And we don't want to load all  controls at the start because, again, the control code base  is also big. So we just load control when it's needed. So when  it's displayed, we asynchronously loaded them. And now we  are also starting working on the lazy loading of our styles  because our CSS are also pretty big. And you might say it  won't matter. But then again, if you have a big code base, you  have 50 developers adding code every day. After some time, it  grows to such an extent that it's hard to control and then it  actually matters in the slow connections. And this is actually  the speaker is from my co-worker blog. So what we have to do  and all of you have to do as well, when the number of users  of your website is growing, the number of features of your  website is growing, you need to keep the page load time constant.  And this is very challenging because you have bigger load,  but you still need to be there. Because it's like, actually it  makes sense, right? You have more users, you'll be slower, right?  But we cannot really do that. We need to go down instead of  going up in here. And you know how to do this? So in this,  you know, simple algorithm here, right? We just measure different  parameters and figure out maybe this will do. We do this  change, then measure again. Is it better? Is it improved? If  no, then try different things. And if it is, then we measure  some other things and we come up with other ideas, how we can do  stuff. And that's how we come up with idea of the relocatable  extensions that we run the client, actually, clients at  JavaScript on the server. And actually, tomorrow there is Steve  Sanderson talk. He is now working on running front-end JavaScript  on the back-end with ASP.NET. So I believe his work now was a  little bit inspired by the work we are doing in the portal.  So this is pretty much all I have. So thank you very much.  And please find me after my session. I will be happy to talk to  you.  Thank you.
Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_0_299.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_300_635.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_636_2891.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_2892_4955.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_4956_5303.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_5304_7607.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_7608_7715.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_7716_7871.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_7872_8795.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_8796_11819.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_11820_15347.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_15348_15455.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_15456_15527.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_15528_16775.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_16776_18563.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_18564_19607.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_19608_20903.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_20904_22871.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_22872_25595.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_25596_25655.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_25656_26447.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_26448_27515.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_27516_28943.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_28944_29147.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_29148_29627.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_29628_29819.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_29820_29951.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_29952_30059.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_30060_30155.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_30156_30911.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_30912_33467.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_33468_34955.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_34956_35207.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_35208_35411.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_35412_35627.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_35628_35855.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_35856_35975.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_35976_39863.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_39864_41003.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_41004_42323.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42324_42371.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42372_42467.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42468_42527.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42528_42635.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42636_42695.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42696_42767.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42768_42863.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42864_42935.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_42936_43019.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_43020_44027.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_44028_45179.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_45180_46379.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_46380_47327.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_47328_48395.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_48396_54263.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_54264_56279.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_56280_56471.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_56472_56843.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_56844_57803.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_57804_58991.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_58992_69395.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_69396_69479.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_69480_69731.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_69732_70811.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_70812_71423.png Azure_Portal_-_the_largest_SPA_in_the_World_-_Jakub_Jedryszek_ORIGINAL_DOWNLOAD_71424_75961.png