 So yeah, we're all set. Hello. And my topic for today is using app.js to manage API resources on my article. So let's talk about the web world today. Today's hot topic is single-page applications. We have lots of front-end frameworks to choose from. We have Backbone.js, Ember.js, and Angular.js. And there's a lot more stuff to it as well. So my focus for today would be on single-page applications and how you can use single-page applications to manage your resources better. So how many of you have used single-page applications? Gmail is a good example of a single-page application. So let's begin with asking a simple question. Why should you be making single-page applications? The very obvious reason is that single-page applications provide a very fast experience. There's no browser refresh involved in a single-page application, and therefore content load. Am I audible? So I was talking about faster experience. Single-page applications can provide faster experience because there's no page refresh. You don't have to load the entire DOM, the entire HTML when you render your single-page application. You just send a request to the browser, to the server, and just fetch the small JSON data. And you can just update the view. We have better runtimes available. We have V8 running in Chrome. And we have SpiderMonkey running in Firefox. And it's getting better with time, which has resulted in heightened expectations. So we have faster computers, faster mobile devices, and everybody's expectations are going higher. So these are the three main reasons why you should be using probably single-page applications. And yeah, so we decided that, OK, that's a pretty convincing reason, so we should make a single-page application. So our journey begins to make a single-page application, and our single-page application is VWO. And we use AngularJS, AngularUI router, and RequireJS for our application. So to begin with, let's talk about models, views, and controllers. I think everyone would be familiar with models, views, and controllers. But in terms of AngularJS, model views are something that is rendered in the browser. So basically, what AngularJS says is that you have a markup and you have basically a template that is rendered to the user. And then you have controllers. Controllers are something that modify the behavior of your view. And then you have models. In terms of AngularJS, models are just pojos. Pojos are plain old JavaScript objects. Pojos are models, plain old JavaScript objects. So pojo means just any JavaScript object, basically. So let's look at this example. We have the controller in our AngularJS application. And we have myController, and we have a controller modifies this property called scope in the view. So scope is something that is shared between the view and the controller. So you can say myModel is equal to helloWorld. And that particular value in that view would update to myModel. And the model, as you can see, the model is a plain old JavaScript object. It's a string in this particular case. So this is what MVC is in terms of AngularJS in a nutshell. So this is the end result. It's just a helloWorld. And this was the start of our journey of making a single-page application. Nothing impressive so far, but let's move forward. So it was easy, but a real model is rather a big and complex object. And usually, it lies on the server. So let's request the server. So we have a service in AngularJS called sgtp, which will answer the queries. We just request something to the server, and it will give you back the model. So what we are doing here is we are scaling up one by one. We are adding to the difficulty level. So here's the code. In your controller, you say you want to get a particular user from the server. And you say, when that request completes, you set the user on the scope. And the scope says the scope is accessed in the template by saying user.name. So whatever the response would be received from the server would be displayed here. So let's assume that the server sends back this response. It gives me a user object with, say, an ID that is 1, 2, 3, 4, a name, John Doe. And email is johndoe at example.com. And it would say, OK, hello there, John Doe. So we haven't been facing any problems thus far. We are stepping further up into the single-page application development. But the problems that come forward are what about multiple views? So what if we want to render the same model across multiple views? What about other kinds of actions? Like I don't want to send a get request to the server and pull the data back. Probably I would want to do it by sending a post request or something. What about multiple types of models? Let's say if I want to fetch a user, but what about if I want to fetch something else, a post or a comment? And how do you handle multiple instances of the same model? So these are the problems that we faced while developing our single-page application. And I'm going to be answering them one by one. And while answering these questions, you also have to make sure that your code is dry, which means that you should not repeat your code. It is consistent. It behaves the same way at all places. It is scalable. You can just keep adding code to it without increasing the difficulty in adding code. And it also has to be testable. So here are the answers. What about the multiple views? So what you do is if you have a model that is shared across multiple views, you abstract it out in a service. So the second question was, what about different kinds of actions? So you already have a service for that particular model. What you do is you add support for those actions in that particular model. So let's say you want to send a get request to the server. There's a method for it. You add a method for it. You add another method for a post request. And you add another method for other requests as well. And what about multiple types of models? So basically, you can provide, you can add a feature to your service that can take a parameter that defines what kind of model it is. So you could create a user model. You could create a post model or a comment model using the same service that we have been using. So whatever we have done so far, it has already been done in $Resource. So whatever challenges we have been facing have been solved by $Resource. Basically, ngResource is what it's called. So $Resource is the rescue here. It is a configurable REST adapter, which means that it has an abstraction of all HTTP methods. So you have a model. And you can use that particular model to send whatever kind of request you want to. You can save, you can get, and you can sync it with the server. And you can add custom actions. Maybe you want to add a custom action for a patch request maybe, or a put request. And it has a promise-based API. So it means your code stays lean all the time. And the resources are loaded lazily, which means that when your view renders in the browser, the resources are loaded on demand. So it does not have to, you do not have to wait for, I mean, you have to wait for the server's request, but the view already is in the, whatever is visible to the browser is already visible there. So if we have to repeat whatever we did previously using $Resource, this is what it would look like. So we create a factory called UserResource, which returns a class, which creates a resource class for me. And it says user slash user ID. The user ID is a dynamic part here. And it picks the ID from the ID attribute that I provide in the controller here. So in the controller, I say scope.user is userresource.get and ID is equal to 1. So get me a resource that has ID 1. So basically, the view is the same. And what you get is basically the same thing, but it is a lot more scalable and testable this time. Because it can scale to a lot of different kinds of resources. You have support for different methods. And it's a lot more extendable. So our journey to build a single-page application continues, and our application grows bigger. And we have several views, controllers, and resources. And then we have editable content. And we face a lot of problems that look like this. So some of those problems include view inconsistencies, duplicated model functionality, and your code isn't dry anymore. So I'll be going through these problems one by one. Editable content. Editable content, what exactly is editable content? Basically, it means that you want to edit a particular model using a form. Let's say you have a user object. You would want to edit your name, and you want to edit your email probably. So what you would do is you create a form, you update, you edit your stuff, and the model should get updated there. So each problem in this particular case is that when you update a model in a form, it should get reflected all across the app, because there's no page refresh, right? So if your model is being used at, let's say, 10 instances, and your view has a single form, you have an editable form that allows you to edit something, it should get reflected all over the app. So that's kind of a problem. So if your change does not get reflected across the app, it results in an inconsistency. So we're going to be talking about inconsistencies. So basically, in a nutshell, an inconsistency is something that says that multiple views went to the same model, but with different values. So for example, if you have a blog, you have multiple posts lined up, and you have your name on all of those posts, and you go ahead and change your name, your name should get updated all across your posts. But if it does not happen, it results in an inconsistency. So why are inconsistencies so bad? So it leads to a contradicting information. Your one view shows something, and another view shows something else, and it leads to confusion. It's worse than having no information at all. So here's an example. We had this code already running previously. Just to reiterate, you get a user with an ID 1, and you render John Doe here. And let's add something more to it. So what we do is we add a form, and we add different controller to it. The form basically does this. The previous view is lined up there. Hello there, John Doe. And there's this form, edit your name. You can enter your new name, and you can say save. But what happens is that when you try to update the name, you should probably update it there as well. But that's not going to happen. If you want that to happen, you want to keep track of that particular object. And update it as well. So that might seem easy, but in a bigger application, it's kind of difficult because you have a lot of places to where you need to update. So what's the solution to this problem? Maintain references of that model throughout the app. So what I'm trying to say is that if you have, let's say, this particular John Doe model, this particular user model, you do not create two instances of that model. You create just one instance. And whenever you change that particular instance, it gets changed everywhere else. So when it changes, you should propagate the change to all instances. So here's a real-world example. This is a screenshot of our app visual website optimizer. So basically, I'm running a new campaign. And my campaign, as you can see, is running right now. So what I'd go ahead and do is I I pause my campaign. And it says the campaign status has been changed. And I pop out another view, which is the campaign list. And it says that campaign is still running. Why would it say that? Because both of those views are referring to a different campaign object. Had they been the same, it wouldn't have happened. So you just have one particular object for that particular campaign. If I change it to running, if I change it to paused, it should get reflected all across the app. So this kind of information is misleading. And it kind of confuses me that is my campaign running or not. And sometimes things can get even more complicated when you want to try to maintain references of unique objects throughout your app. So when you're trying to edit a resource that is linked to multiple parent resources, for example, you have an author. The author could be an author of a post, or it could be an author of a comment. Maintaining references here isn't so trivial. So in the previous example, I would say that I changed the name of the author. And I have a reference of all the authors with that particular idea, and I keep updating them. But it's not so simple in this particular case, because you have to go and track every post by that author and every comment by that author. And it's not performance intensive either. It won't be performant either. The solution here is relationships. So what you do is you define relationships to handle sub-resources and also maintain a single reference for each unique sub-resource. So let's talk about relationships. So what relationships mean are is that a property on a particular resource belongs to another resource. What do I mean by that is, let's say I have a post, and a post has something called, who is the author of that post? That particular property author is related to an author resource. This is the example. Post.author is an author resource, and author.post is a collection of post resources. So if we can create a way to define these relationships, our problems can be solved in a better way. So there are four kinds of relationships you might know of from relationships in mathematics. One-to-one, one-to-many, many-to-one, and many-to-many. So as you can see, the post.author is an author resource. It's a many-to-one relationship, because many posts can have the same author. And author.post is a collection, and it's a many-to-many relationship, because multiple authors can have multiple posts. Let's go and let me show you an example from BW again. We have an account, and we have a lot of billing cycles. We have a billing cycle. Each billing cycle has, again, users just attached to it, and the users just are by account. So basically, we have five billing cycles here, and each of those billing cycles tell me which account consumes a lot of visitors. So this is what the relationship diagram looks like. An account has billing cycles, and which is a collection of billing cycle resources. Each of those billing cycles has usages, and usages, again, are related to account in a many-to-one relationship. And each of the usages also has a number of visitors used. So by creating a way to define such relationships, we can solve a lot of problems about scalability and maintaining consistency throughout the app easier. So the subsequent problem is maintaining references. So you have defined relationships, and how do you maintain references of unique resources? Talking about references, a reference is a unique. What I mean by references is that every unique resource has only one instance throughout the app. For example, there should be only one user resource, which has ID1, and there should be only one user resource, which has ID2. And similarly, there should be only one resource with ID1. What I'm doing here is that I am trying to identify those resources by a common parameter. In this particular case, that parameter is an ID. So when do you create these references, you transform every back-end response. So it looks like a job for a transformer. So a transformer is something we created to take any input from a back-end response object and convert into a mesh of resources. So basically, what it looks like is this. I say I want to get all the posts in my particular blog, and I say I have three posts. And two of those posts are by John Doe, and one of those posts is by Johnny Ive. So you want to, just a second. So the output I would expect from a transformer is that, so as you can see, there are three items in the array, and I would expect the created-by-property of each of those resources to refer to a single object. So what I mean by that is that the output is an array. It has three items, and each of those items is a post resource. And I would say that the first and the second post, all of those posts are created by the same user, so their user object should be the same. So we would use the transformer to do something like this. So in a nutshell, if I have to explain what exactly we are doing is we are scaling by abstraction. Basically, we are trying to solve the same problem across multiple resources across the app, and trying to index the resources and transform relationships. We are trying to do a lot of stuff, basically, and we want to abstract out the core functionality from whatever is configurable. So what you do is you define your relationships at a particular place, and you create a schema, and the end result would be an abstracted base that is scalable, testable, and configurable. So it would prevent mixing of your resource management logic with the business logic. So you would say this escalated quite quickly, but let me put it all together once. So we have relationships, we have resource transformation, and we have indexing. So I think I skipped the indexing part here. The indexing means that if you want to identify unique resources, you want to maintain a hash map of how to identify those resources. So in a particular case, let's say if we have a post, it should be indexed by ID. And similarly, every author should be indexed by ID. And we have a configurable schema. A schema is where you define which resources related to which resource. So it is a lot like amber data for AngularJS, what I'm talking about. So the result you get is resource manager. So let's talk about resource manager. In a nutshell, what it does is it takes a server response, it passes on the response to a transformer, it uses a schema to identify which relationships to apply, and it uses a data store for indexing everything. And your application requests the resource manager for a particular resource, and it gives it back to you. So as I was trying to explain earlier, this abstracts out your logic from your business logic. So it's an abstraction of problems we face while developing VWO. And a lot of them have already been described in this presentation. And we're going to be open sourcing it soon. So journal learnings from this particular presentation and this journey of ours about VWO is that abstract or duplicate logic and configurations from the logic. So when you're trying to quote something, you should figure out what is configurable. You should probably define a schema or a pattern. And you should abstract out logic. That way, your logic always stays small. And it is scalable and highly testable as well. Think recursively. Think recursively. And you should research along every step. You should keep learning more about AngularJS and other libraries. In our particular case, this library that inspiration from was EmberData. So I think that's about it. If you have any questions you should ask. And you can reach out to me on fleerun.org. And if you want to view this presentation, you can visit this particular URL. Any questions? Hi, Manchu. My name is Mandi. Hi. My question is a bit off topic, but it's related to single page apps. OK. OK. I was building a web application. And I was using RequireJS and Backbone. So we decided to make it single page. But as the application grew, there were more modules and more files. So eventually, when it grew, the app became slower. So we decided to use optimizer of RequireJS. OK. So what happened was via the single file, JS file, the size of the file got pretty large. So we were in a dilemma whether we should still optimize it or just keep it as a single page. So we were able to decide. I think if you would want to use RequireJS Optimizer, can you repeat the question, please? OK. So what happened was when we used Optimizer, the file which was generated, it was pretty large. So when the user loaded the app for the first time, it took a while to download that file. And after that, the app went smooth. So what you can do in this particular case is you can load only the files that are required for that initial view to render. So let's say in our particular case, it was the login page. So what we would do normally is we would just load the files that are needed to log into your application. And then meanwhile, while the user is performing something on that particular page, you would transload the rest of the application in background. So it would take the same amount of time to load the application, but the perceived loading time would reduce dramatically. OK. Thanks. Any other questions? Hi. How do you maintain client-side state in single-page app? Just a second. Client-side state is maintained by Angular, UI, Ractor in our particular case. But if you're talking about models, they are maintained by our library that we have written resource manager. So it basically has an entire database on the front end. So if you are familiar with amber data, it's kind of like that. You would have a lot of resources on the front end and local storage as well. And it would request the resource from that particular store. If it doesn't exist, it would request it on the server. So for maintaining states, we use Angular UI, Ractor, as I said. On every state transition, we figure out what kind of resources we need to load. And we use that for transloading resources when that particular view renders. So does it answer your question? Yeah. In case of like, if you have a list of resources and if it has some filter, some list of resource, consider some post. So for that, you have some filter on the left side. So while navigating to, while moving from one filter to another, you just paginate it. In those cases, if you need to maintain the state, so how do you do that? So there are several ways of doing that. The first obvious way for me would be to use the filter on the server end. So while you're paginating, if you go to the next page, you would fetch another resource from the server. So basically, in this particular case, you would fetch a collection of resources based on the page you are viewing. So it would be passed to that resource manager. And based on whatever view is being displayed, the model would load correspondingly. In case of single page apps, we normally use the syntax that is given. Actually, do we have any tools to identify memory leaks in case of page freezing? Yes. In our particular case, we use the Chrome timeline for identifying which parts are taking a lot of memory and which part is taking a lot of time to render. And you can use the JavaScript profiler in Safari or Chrome to debug your heap allocations. And you can see with exactly which particular object is taking a lot of memory. So you can work around it. You can also optimize CPU performance using the Chrome profiler. So you're using the dollar resource, right? So does it have any limitations in terms of browser compatibility, like IE9 and all versions? It does not have any browser limitations. The AngularJS entirely itself does not support IE8 anymore. But all the new browsers should really support it. In other questions, does it support all verbs like you do? You are put, delete, or get? So does it support all verbs? Yeah, not only does it do that, it also allows for you to add custom actions, which basically means that you can add your own custom method type. And you can add your own handler. You can add custom parameters. It's really configurable that way. I mean, OK. So it also has all the wrappers of all HTTP, right? Sorry? It also provides all the flavors of dollar HTTP, right? Sorry, it's not audible. OK, it also provides all the wrappers of the HTTP provider, right? Yeah, yeah. It's basically a REST adapter in the simplest sense. OK, thank you. Thank you. Any other questions? Hi, Manishu. One challenge with SP applications are that how to maintain this search engine optimization. So in your case, how do you deal with it? Our single page application is behind the login page, and we don't really care a lot about single page application. Sorry, we don't really care about SEO in our particular case. So I know it's kind of a hard thing to track. But I think a lot of bots these days are capable enough of parsing JavaScript. And it should not really be a problem. The SEO should not really be a problem in today's world. Any other questions? So I think that's about it. If you have any questions, you can reach out to me on my email ID, or you can just catch me outside. Thank you.