So this session is on test driving a jQuery plug-in. Just a disclaimer, while this is about test driving a jQuery plug-in, this is also about test driving any JavaScript. There wouldn't be much of a difference.  So I'm kind of trying to push in a bunch of different things into this talk. It's a demo, so I'm going to be live coding pretty much throughout. So if you get scared seeing code on the screen, probably this session is not for you. So with that disclaimer, I'm going to get started. I'm going to talk about for the next 90 minutes, this is basically what we want to cover. We're going to quickly spend the first five minutes just doing the basic setup. So we have all the prerequisites that we need.  So we'll spend about five minutes, show you how trivial it is to set this up and get up and running. Then onwards, I'm going to try and basically... So I built a jQuery plug-in for Commence. And that's what basically we want to try and do is how to test drive a Commence plug-in. So if you have any website and you want to have Commence in there and you want to use jQuery to do displaying your Commence and other kinds of things, that's basically what we're going to try and do. And then we're going to try and show you how to move towards an MBVM kind of a design pattern for a jQuery plug-in, which I think not many people talk about that, but that's something that I want to try and attempt in this particular live demo.  All right, is that cool with everyone? So that's a quick snapshot of the actual plug-in that I was talking about. So this is if you use Confengine, which is our submission system, basically the plug-in that is there is built using this. So I'm going to try and obviously we're not going to get all the way through doing every single functionality in this. There's a lot of functionality going on, but you will probably see how we can approach this particular problem if you were to build nested comments, if you were to build private comments, other kinds of features, a whole bunch of different things. So that's basically what I'm trying to tackle. How many people are familiar with test-driven development? Just a quick show of hands. Okay, awesome.  Just show up your hands. These are the guys, you know, if you ask any questions, these are the guys who will answer it, because I don't know much. Let's, for the benefit of everyone, let's quickly touch upon what is test-driven development. What's the idea behind test-driven development? So we start with an automated test. We start with a automated test, not a suite of automated tests. We start with a automated test. We run the test, and what do we expect to see? We expect the test to fail, right, because there's nothing. All you started with is just a thing. And sometimes, however, you will find that your test passes. So what do you do then? Be suspicious. Something's wrong. Most probably, your test is wrong, right, because it can't just pass without actually having it. So ideally, you would expect it to fail, and then you want to make a little change to the code. What do we mean by little? Few seconds, few minutes at the max worth of work, not few days or weeks worth of work, right? That's one of the big mince conceptions. People write a test, and then next three months, they're writing code. That's not a test-driven development cycle. The whole point is quick feedback, very short feedback cycles.  If it fails, we continue making changes. If it passes, what do we do? Go back and write another test, right?  It doesn't work. Why? Yeah, you pretty much kind of go and become DHH at that point. And you don't quite understand what TDD is. Sorry, DHH, but that's true. So when you have a passing test, the important step that people often forget is that you need to refactor. And in fact, a large portion of what I'm going to be doing is actually showing you how cool refactoring is and how cool refactoring can make your design and simplify things. So refactoring is essentially an important step of what we call as a reflexive design. So it essentially helps you, you have some little code, and you look at it and you say, you know what, geez, there is duplication in it, or this is not communicative. This is not simplistic. Can I improve the design to make it better? Right? So it's very easy for anyone to hack a jQuery plugin, you know, 15 minutes, max is what it takes. But actually to write a good one that anyone can understand and anyone can contribute and modify actually takes a lot more effort. And that's where I think refactoring becomes an extremely important step.  So we always refactor code when we have passing tests, because we want to make sure that when you refactor code, you don't break any functionality.  But the idea is that you refactor, your test should always be green at that point. And then you repeat the cycle. That completes one TDD microcycle, right? And this is essentially what we're going to try and do for building a jQuery plugin. You can do this for all kinds of things, but that's basically the nutshell idea behind test-driven development. Right? Everyone on the same page? So I meant this to be more like a, you know, program along kind of a session. So I have set up a GitHub repo and you can download the project and get started. It has just basic structure in it. So we're going to try and do that. So the first step is whatever, create a folder where you want this thing to be. Git clone this repo. And then once you've got, you've done the Git clone, you're going to get the JQ comment demo. And post that, we're going to do an NPM update. So I'm going to go back for the benefit of people who couldn't see the Git repo. It's actually a bad idea to fade these things out. So let me not do that real quick. That should fix it. So Git clone that repo. I'm going to go into that NPM update. I have done some of these basic steps on my machine. So I'm not actually doing it right now. I was not sure if the Internet connectivity will hold up. So if you do an NPM update, it's going to bring in all the dependencies that you need. So there's already a JSON file that the package that JSON file is there. So it's going to bring in all the dependencies. There's one thing that we will be using Karma. And if you want to kind of run things from the command line, it's a good idea to actually install the Karma CLI. And generally we install it at a global scope so that it's accessible anywhere. And this is especially important if you want to run things through your CI server, any kind of Jenkins or whatever. So it would need access to Karma to run this. And then we're going to do Karma in it. So I'm going to start showing from this point onwards. Let me mirror my screen quick. Get rid of that. That chops off my screen which is not very good. This one's luckily that should not be too much of a problem. So we want to do a Karma in it step at this stage. So I'm going to go through the project. I have already checked out. I have these files in there. So if you're following along, this is essentially what you will see on your machine at this point. And then I'm going to do Karma in it. And it's going to ask me what framework you want to use, your testing framework. So in this case I'm going to use Jasmine. It says do you want to basically use required JS to manage your dependencies now. Capture what all browsers. This is again a cool feature where you can run your tests against a whole bunch of browsers and make sure that it works in all as you're building stuff. So I'm going to say Chrome. You can tab out. I'm going to say Firefox, Safari, and Phantom JS, or Phantom JS, which is more for a headless browser. It's a headless browser. So I'm going to run all my tests against those four browsers right now. It says specify any location where you're going to include your source or test file. In this case, I'm going to say lib slash star star slash star dot JS. So I might have some libs that I want to include. Then I might have JS slash star star slash star dot JS. And then, yeah, it's saying that no file exists. That's okay. And then the last is I generally put all my specs or my, I don't like to call them tests, but if you will under this directory. So those are basically the three. It's going to one again. The spec does not exist. We're going to create all of these things. So those are three things I want to include. I don't want to exclude anything at this stage. I don't want karma to auto run the test. We're going to run it ourselves. And then that's pretty much it. It's produced a basic configuration file for you. So let's go in to PHP storm, which is what I'm using, but you could be using web storm or any other ID of your choice. You will see that it's added karma config.js file. So whatever we put in libs here, you can come back later and change those things. It's added jasmin, which is the framework we're going to use, a bunch of other configuration and the browsers that you asked to use. Everyone's cool with that? So what this gives us is this gives us the ability to basically now run the tests. We obviously don't have any at this stage. So we're going to go ahead and create one very basic one. So I'm going to say create, let's say, I'm going to call this as a command spec.js. Let's call it commence spec.js. Yes, go ahead and add it to the repo. And what do I need? I need to describe what my spec is going to look.  So this is basically jQuery comment login. Don't have any bars at this point, no setup required at this point. And usually the very first test we want to make sure is everything's hooked up and ready to go, so it should find jQuery. So I'm going to say expect $0 to be null. This is, again, what we're using is jasmin syntax here, just to kind of do the verification for us. So this very basic test, what it's trying to see is, okay, I'm set up, do I have jQuery available so that I can proceed from here? So when we try to run this, the simple way to run this is basically click on this and I mean you can right click on this and say run as spec. And notice there it started all the browsers that we wanted. So you'll see it started Chrome, it started Safari, it started Firefox, and Fandom.js, which is a headless browser you wouldn't see, but it ran against all of those. And there it is, it says all our tests are green at this point. So in all these browsers, we are able to find the handle to the jQuery. This is pretty much, we're going to delete this at a later point, but this is a good starting point, this tells us that we're all set up. Is everyone with me so far? Very simple, just getting started. Now next thing what we want to do is we want to basically write a spec which says that, okay, so actually let's switch back real quick. Let's talk about some of the actual features of what we're going to do. So create a symbol spec, we just did that, and we ran Karma test. Another way to run Karma test, I'm going to show you that a little later. But before we get into anything important, let's have a quick commercial break. So my name is Naresh, I live in Mumbai. I was a partner at a company called Industrial Logic where we built eLearning for people. One of the things we take pride in is every Google employee used to go through this eLearning. I left the company, I started another company called Adventure Labs where we built games for kids to learn mental arithmetic, so that's fun.  I run a lot of conferences. That's something that I've been doing for the last 11 years. I've been running a lot of conferences. These are all more of side projects in some sense. This is more for kind of building a community here. So a shameless plug for the functional content that is coming up. If you're interested in functional programming, this is the second functional conference that we're going to have. You can look at the videos from last year. I have a little startup called Confingent which basically builds all the management software for a conference or signing up and things like that. That's basically what drives a lot of these conferences and things like that. In the past I've worked for these companies either as an employee or as a consultant, so that's kind of my quick background about the places that I come from. It's a pretty long list. So that's enough about me. Let's come back to the project. We'll talk about what we're going to try and do. So what we're trying to do is basically build a plugin which has some of these features and many more, but today hopefully we can try and get to these features, which they should be able to accept comments either as a JSON. So you give it as data. If you've seen most jQuery plugins, they either accept a JSON as a data and then it does whatever it needs to do. Or you can give it a URL and it'll do a call for you and fetch the data. So we're going to try and do both of those in this case. What you also want to do is you want to show the most recent comment on the top. That's one of the features we want to build today. You want to have the ability to mark comments as private and only the author of the comment can see. In our case, the author and the program committee can see, but here we're going to not bring the committee into it. We're going to keep it pretty much like if it's private, only the author can see it. So some functionality to show this is real and then you should have the ability to like a comment and things like that and so forth. So that's what we're going to try and get to today. Everyone with me? So what's the first scenario? The simplest thing I can think of is we have no comments to display and we just need to show something like be the first one to add a comment. That's the first spec we're going to try and get to. If you guys want to come in, there are a few more chairs over here that will help other people come in after you. I'm going to try and see if I can fix my screen real quick because this is not the best. This is probably better. Can you see the entire screen now? Yeah, that's much better. Make sure you can see that. Okay, fantastic. I will increase the font size of this as we get into this because this is where we'll be primarily working. And I think that's pretty much what we care about at this stage. So let's write the next spec. What is the next spec? Should display a nice message when no comments are available? Right? So what do we expect? Now this is where we need to do the basic setup of our plugin itself and create that so that's what we're going to do in this step. And we want to expect that, you know, whatever our... So I'm assuming we're going to have a div which says hash comment as the ID, comment as the ID, comment as the ID. And we're going to plonk in whatever we get. We're going to build and put it into that div ID, comments ID. Right? So let's quickly set that up. So one way to do that is there is something called set fixture and you can pass in a bunch of HTML into it which will just create your basic fixture that you need and we need something like div ID equals comments. This is where my comment should go. We're saying this is what is the prerequisite before we get started. So set that fixture and then you should be able to say var commands equals $ and then here what we want to say is comments. What can we do? We basically want to now see what's actually in the comment after we run our plugin, right? So that's our expectations. We are saying the comments.html should be what? Be the first one to comment something like that. All right? Now we need to actually set up our plugin. So we're going to say comments. So you can call any method which is a jQuery method now on this. So we're going to say jq comments which is our method and this is basically invoking the plugin at this point and it should do whatever it needs to do and then this is what we should get back. Now obviously we don't have this jq comments because we've not created anything. So let's go ahead and add a folder. This is where we're going to get our JS into it and I'm going to add... So I have a little plugin thing here. It's called jQuery.commands. And so what it does is basically creates as per, you know, some recommendations from jQuery community around how you actually create your jQuery plugin. So you want to wrap your whatever function you have inside an executable, inside anonymous function so that it doesn't leak scope or things like that. Bigger text. Oh, sorry. All right, sorry about that. Is this visible? This is fine. Maybe a little bit bigger. Okay, so we've got ourselves an anonymous function inside which we are adding a single thing. We're not going to call this this. We're going to give this our actual name, jq commands. That's what we called it. And here we can do whatever we need to do and then basically return this so that you can chain your jQuery plugins. That's just the basic setup. If you wanted, you could write a test saying that you can actually chain up. So you could put an expectation saying that it returns the container back when you call the jQuery method. So you could do things like that. I think because I'm just using a template I wouldn't probably write a test for that but you sure could write one for that. So here what we want to do is basically we are saying this dot append. In this case we're going to put whatever we want to append into this. And we're going to see how we're going to evolve this. So that should be pretty much what we need. Actually we don't need another step because we've already said include everything in the lib, include everything in the js folder. Again I'm going to increase the font of this so you can actually see what's going on here. We've asked it to already include these things. Our plugin should be included. Let's run this. And we expect it to fail. Sure enough, it did fail. So the first test still continues to work. The second one says that can't find references to set fixture. That is because we need to add another. So the set fixture comes from another plugin that I'm using. That's basically, let's get this guy. It's called Jasmine jQuery. So Jasmine jQuery is a plugin which will provide those methods for us. And now it says expected undefined to be the first one to comment. So now everything's hooked in. We're not obviously doing anything inside our plugin, so it's giving an undefined. And we expect it to basically give that comment out. So what's the way to make this work? So inside our actual jQuery plugin, we're going to just put in that statement here for now. Be the first one to comment. Because there's nothing else right now you can do. It's going to hard code that. See if the test passes. Undefined to be comment. So, whoa. Oh. Sorry. Thanks. That actually works. Now you will notice that it's running Safari a bunch of times. That seems to be a weird problem with Safari, where it's opened a whole bunch of tabs. Every time it shuts down, it opens the tabs again, even if you tell it to start a new browser. So I'm just going to close that. So it's going to have just one Safari, one Phantom, one Chrome and one thing. So there are eight tests because there are two into four browsers. Right. Okay, so far good. Very trivial, basic stuff. No fun. I mean, this is any kid can do this, but this is we're going to try and make this more interesting. But this gives you the basic idea around how we are approaching this. Right. Let's go into the next spec and try and make it a little bit more interesting. So this is when you actually have a comment and you want to display a comment. And we're going to start with just one single comment and then we're going to build it to multiple comments and other kinds of things. So I'm just going to take a copy of this. And say should display a single comment from data. Now, obviously, as the moment we do this, we notice that there's some duplication which we can get rid of. We will come to that in a minute. And here I want to pass in basically to start with, I'm going to just pass in, let's say data colon. I'm going to make a little bit of a jump over here. I'm going to introduce the data colon and then pass in JSON. I could have taken a more smaller step and just passed in the JSON as is and then added it into, you know, but I'm trying to make this more like an options that you're passing in because these are different options that you're passing into the jQuery plugin. So this is again another JSON where let's say we say I have some kind of a message which is let's say first comment.  So what we are saying is we are saying jQuery, you can take an optional data option which has an actual jQuery, sorry, a JSON comment that could be derived from the server. In this case, we are directly giving it to it. And then what do we expect here? Something different. We're going to start simple. I'm going to say first comment-narration, right? We're going to then later go in and put some structure to it and make it look much better, but this is, let's take more baby steps here. Sure enough, I run the test. It always returns be the first one to comment, but we are actually expecting something different. So what do we need to do here? We are taking in ops into our function here right now, right? And then, again, the recommended way of doing this whenever you get some options, you have a default and then you map it onto that so that you're providing the ability for people to have the defaults and extend those defaults by passing in. So I'm going to just say var defaults. What's the default? Data with some empty JSON is the default. We're going to add more options as we go along, right? Now we only have one option, which is the data option. And then you're going to say var options equals $.extend and you're going to say defaults and then take the options. This will ensure that if you override any of them, it'll, if you, if you pass in data, it'll override else. It'll give you the default, whatever you set in.  And now we are always sure to have some kind of a JSON, either an actual JSON or an empty JSON, right? So here we can check if what? What do we want to check? There are two conditions here, right? One condition is if nothing was passed in, which means that the data JSON is empty, right? So options.data is empty, right? So we can check. I don't know what's the best way to do this, but has own property and I could pass in message. If it has own property, then I want to do something else. I want to just stick that in. So if it has then this.append, what do I want to append? I've got options.data.message plus iphone plus options.data.user, right? If this, this, else, that, and return. Let's see what happens. Sure enough, the test passes, right? This is not beautiful code. I'm just showing you very basic steps of how we're going to go and then we're going to step back. So what do we need to do now? Now we want to look at it and say, hey, how can I improve the design of this? Even though we've written just like four lines of code, we still have a lot of scope for improving the design over here. So we want to do that and we're going to start with our tests. Remember we talked about this duplication between these guys, right? Why do we need to duplicate this over and over again? So we're going to try and move this up into our before each and we're going to try and move these guys up into the before each section. So you don't need that here. The only thing is you'll have to pull out this work outside, so it's accessible. So there we have got rid of some duplication and simplified this a little bit. Then the test still works. No problem. What can be done here to simplify this? Or this is simple enough for now. I would say it is not the best, but it's simple enough for now. When we write the next functionality, this is going to make this more complicated and at that point we will come back and refactor this, right? So what's the next test you would write? It's the next spec you would write. Passing in multiple comments, that's going to push us down a certain path. So let's try to do that. So actually, before we go there, actually what we had said is that we would probably like to put some structure to this, right? If you look at a typical comment that I showed you in the diagram here, wherever it is, there is some kind of a structure. So there's a header of the comment. There's a body of the comment.  So let's try and put some structure in so that, you know, we kind of start building something real quality stuff in right away, right? So what I actually want to do is I'm going to change the expectation here. And instead of saying this .html, we can say . to contain element. So to contain text is one thing we can do which just replaces that. So we don't have to, we don't have to do .html internally. This should still work. Let's make sure. Yep. What if we are just smoking up stuff and none of this is actually going to work, right? So generally like that's a question that always comes up in my mind. And I always prefer to have some kind of example .html that I start building along with my plugin. So as I build my plugin, I also have an .html which actually does it. And once in a while I go and look at actually is it rendering the way I want it, which kind of gives you the confidence that, okay, this is actually real, not, you know, just all up in the air. So let's go and, you know, I have a basic dummy .html. So we're going to try and add that in here. So we want to include. What all do we want to include here? Increase the font size. Why do I forget that always? Okay. So I want to include here my .js and this is .jquery commence. That one thing I need to add, then I just say commence.jquery. What did I name this again? Let's go make sure it's called commence. So here and then we are at this stage passing in a kind of array to it. So let's pass the same thing over here just to see what actually shows up. So I'm just going to copy this from here, put it in my .html. Okay. So if I go now to another .jquery instance, which is running at a local host, or you can run it through a file, .jquery demo example. So there, sure enough, it does show first comment the way we want it. So, you know, our tests are actually quite realistic. Once in a while, still it might make sense to go and look at this and build the example along. For example, who will use your plugin, have an example ready to go. Right? Everyone's with me so far? So we've done some basic refactoring here. We are still left with some more. We are saying that we want to put some more structure to this like a header and a body. So for our comment, and then we're going to build it out that way. So right here, what we can do is we can say expect. Expect commands.toContainElement. And so if I don't have anything, I expect it to contain an element called div.empty. So I want to put something so I can do nice CSS on top of it.  So I can say .fine and then I can pass in this CSS selector into it. So I'm saying find this div.empty and that should contain a text. Be the first one to comment. All right? Similarly here, I would want a kind of slight different structure. So I'm going to just copy that. So comment.contain. So now it should basically have a div with comment as a class on it. And then how many of these would you expect now? This.size. What would you expect the size of this to be? Size to be one, right? Because we only provided one comment. You should only have one. It should not do something else. And then lastly we want to make sure that this guy.contain.text. So if I run this, it gives an error. That's interesting. Yup. So find and then there is a parenthesis missing over here. Good. Okay, first test is passing. Then the next two tests are failing because we made some structure changes which is not reflected in the code yet. So let's go back and make those changes in the code. So what would we want to do here? We are saying that when we show this actual message, we want to put some structure to it. And similarly we want to put some structure when we are going to do the empty one. So let's tackle the empty one that's easier to handle. And then, so we're going to say this, let's say, empty equals, what do we do next? Add class, right? What's a class name? Empty.append, which is essentially what's down here. Add an empty div and then add the comments inside that. Whatever text we want. And this empty is what we want to then append to our container. Same thing here but a little bit more complicated. So we're going to create a div, let's call it header. That's the header. And this should contain what? In our case it should contain the option.data.user. And similarly we're going to create another one which is going to be body. And this should contain the message. And lastly we want to create a comment itself, which is a div which contains comments, if I can type. And then this would basically append first the header and then append the body. And finally we can then simply say append the comment. Let's run the tests. Still one thing failing. So it's expected this whatever object but it got first comment, of course. Why did it get first comment? So it says to contain. Somewhere I think we've not updated the tests. Oops, my bad. This should have said that it contains one comment. And then we could say dot header. Space dot header to contain the name of the person. And then dot body to contain first comment. We made some structural changes. We're back with the test passing, right? Is there any problem you see with this approach that we're doing here? Is this fine? Some repetitions are there. There could be refactored, right? But more importantly is like going and looking at these selectors and doing this. Is that a good idea? At this stage I would think it is okay because otherwise it would be an overkill. But once your plugin starts getting very complicated then trying to do something like this might be not a good idea because you're now trying very closely to the structure. Maybe you want to have, pull that out. So that's where we are going to head to is basically separating out a view and then trying to do things on the view, separating out the model, trying to do things on the model where you don't mix up the structure and the actual data, right? So that's where we want to go and that's the problem we have right now over here, right? But for now this is not too complicated so we can live with this. Once we start doing a completely nested structure, we start doing adding lot more things. We start adding events to it. This will become extremely difficult to maintain, okay? So again we are just building step by step so it is okay for now but don't go back and think this is the best way to write your Jasmine tests. All right, so all tests passing. Let's go back to our guy over here and see what happens now. Let's put a little CSS on it so it looks a little pretty. So just going to create a directory CSS and just going to add a style sheet. What do we call this? jquery.commands, keeping the convention. And I just have this handy comments over here that I'm just going to plunk in because I don't want to spend time writing CSS right now. All it does is it just gives a little border and color and things like that. And then in our example we want to add the CSS so we can actually load it from our HTML. And that would basically be jquery.commands. So if we now went back to this guy, refreshed it, you see some colors and borders added to it, okay? This is very basic but kind of taking us towards the direction where we want to go. Now there is specific tools available if you want to do specifically CSS related tests. So there is a unit testing framework for just doing CSS related stuff. That's kind of out of scope right now. I'm not going to go into that but just want to mention that it does exist. Let's go back to our thing and that's where the fun is in the next test is when we want to make the leap and convert this into something more interesting.  All right, what's the next test we want to do? Multiple comments, right? Multiple comments would make sense. Display should display multiple comments from data. So here we have, now again we're going to start duplicating some of these things. So I was thinking what we could do is just take this out, create a variable called first comment, something like that.  Similarly here you can now refer to this as first comment. But now we want to pass multiple, right? So we want to convert this simple stupid JSON that we had into an array of JSON because that's what your server is going to return an array of JSON, how many ever JSONs you're going to have. So let's convert this into an array. Let's do this guy as well. And here we're going to create another JSON which is the second guy. So this is again message second comment. And then the other thing was user colon some other name. So now we are passing in an array of JSON objects as comments, as data into this. And then what do we expect here? We expect size to be two. We expect the first header to have this. And then we expect the last in this case because we only have two to be Jack. Everyone with me so far? Let's run this and we have test failing. Both the tests are failing because we did change the structure to an array instead of just a JSON. So let's go back and fix a couple of things real quick here. Let's make this an array as well before we forget that. And let's go back to our actual plugin. And here we understand that this is now going to be an array. So the default is an empty array. Nothing's in there. Let me just write. And then here now the options you're going to get the default options. This options guy is now not going to have data which has own property, but it's going to be an array. So this is going to basically now what we can check and which actually I like better is that now we can check if that data size. If the length of the array is not equal to 0, then do this else do something else. So if the length actually I like to flip this now. So if it is equal to 0, which means you didn't pass in, it's an empty array, then do this else do whatever you need to do. Now in this case earlier it was very trivial. We could simply just add one. Now we need to do something more than this. So let's extract this guy as a method. I'm going to pull this guy out at the global scope right now because I'm trying to move these things out of the plugin itself. And what do we call this guy? This is basically build, comment, HTML. So what that did is basically pull this guy out here. It's not a recommended thing to just put these in the global scope. It's just an intermediate step. We're going to fix that. But what it did is basically pull this thing out and it has a few more issues. So what we want to do is instead of passing options, you're going to pass in a specific comment. So instead of doing that, let me just rename that to C and then this will become C dot whatever. C dot message and C. So from here what we're going to do is now I could say dot data. But data is actually an array. It's not a single comment. So we actually need to now loop over this data and construct this thing. So we're going to have some kind of inner HTML element which I'm going to build. I'm going to tell you in a minute why I need to do that. So let's get ourselves some kind of a div and in this div basically I want to loop over all my options dot data. So I'm going to say options dot data dot for each if that works and that takes a funk which takes the comment. That takes the comment and what do I do? I basically say inner HTML dot append. What do I append? This guy. But not the entire options instead each comment. That's going to basically append this whole thing and this and then what do I have here? I have inner HTML dot I have to do that to get out. I don't need the div. I just need the body of it. So it's going to get that out. Am I done at this stage with this basic stuff building comments HTML and passing the other nice thing you'll notice is we are passing dollar to it instead of assuming the dollar is there. This ensures that tomorrow you flip from jQuery to something else. You will pass that all along and then you could do whatever changes we get to that part but we kind of going down in the path that this should be kind of completely decoupled from what library itself you're using. And so you should have the ability to pass in its kind of dependency injection, which is a big word, but that's what we're trying to do. Instead of assuming that there's a dollar and I always can access the dollar from wherever. So the test does pass. No brainer. But what this help does understand is that you know what this building HTML business does not actually belong to your actual jQuery. Right. So that's something we want to pull out of this. Right. And there's some more stuff that we are doing in here which actually does not belong to the plug in itself that can be pulled out and it's quite independent of the plug in itself. Right. So what would you pull this out into? Would you pull this out? That's also doing some HTML ish stuff and it's nothing to do with jQuery per se. Right. So we could technically pull this out into its own global function and we could call that as an empty command HTML. Can we keep it in there is what I'm trying to do is move this to a view class because this really belongs on the view. A view object if you will just move it all on the view and let the view handle the HTML portions of it instead of the plug in itself having to deal with the HTML. Into .html file. That's another thing. So you could have it in the HTML file and just include that is what you're saying. Right. Look it up as and this included. That's that's also possible where I'm going with this is trying to make it mostly like pretty self contained functional in nature. But that's a valid approach as well. So this basically pulled it out. It does whatever it needs to do. And here you will notice that now I don't need the I could inline that thing pretty easily. Is everyone with me so far? I don't like this this dot append twice. So I would like to basically say war HTML content if I can type. And here I want to basically take this guy assign it to the HTML content. Same thing I want to do here is take this guy assign it to the HTML content. And then only once basically do this dot append HTML content. What that basically means is that this whole section that we have now could actually be pulled out. And this would return you whatever HTML based on the options that you've given to it. And then that's simply what you're going to append or that's what you're going to bind to your container and return. So I'm going to pull this out as another global method. We're going to call that as to HTML. It's got a typo which we're going to fix. So it's pulled out another function which basically does the construction of the HTML. And now let's look at our code and code plugin code itself. Is this much easier to understand and maintain? This is the core of what your plugin is doing essentially. Obviously we'll add few more things into it. But rest all stuff can now be converted into actual objects. And then you could start modeling this in terms of some kind of an MBVM pattern or whatever pattern you want to use. Let's run the test. It's been a while. All the tests are still passing. I said once in a while it's a good idea to go and check how does our UI look. It looks pretty good. Actually let's do one little quick thing over here. So this example has only one comment. I want to give it the second comment and see how it actually would show up. Just to be sure we are not smoking something in our own world. Sure enough. Still works. All right. Now we can pretty much close this for the time being. We could go ahead and convert these into... So one of the things you will see is that we are passing the dollar to all of these things. And you could essentially convert this into a view class at this point. Which would have a bunch of private methods and one public method that exposes which is basically the two HTML method. And it's going to give you the final HTML, do whatever it needs to do with it. So that's one step we can take. We can go into that direction. The other thing is we can say, okay, what happens if we start adding some logic now? Like the logic of maybe private should not be visible. Only certain things should be visible or things like that. So any opinions which direction we should go at the next test or further refactor this into making this as a view class. Refactor. All right. So I'm going to go with that because as I said earlier, TDD is a lot more fun if you just refactor it all the time. So what do we want to do here? So notice this two HTML method. This would essentially be on some kind of a view class, right? So let's create some kind of a comment var comments view equals, I'm going to say new. I don't have any comment view as of now, but I'm assuming somewhere there will be a comment view reminder. And I'm going to pass the dollar and the options to it for the time being, keeping the same. And then this method that we have, we're going to call this on comments view dot two HTML, which probably would not need to take anything. Yep. So let's create our function. Let's give that a name comment view and this guy is taking in the option and the dollar. And we need to just do this dot options equals options and this dot. Now, I mean I could do this, but I'm going to just say take you from now. We have that and then that gives us the object. And then this two HTML should now belong on the prototype of the comment view, right? So we're going to say comment view dot prototype dot two HTML equals this function which doesn't take any of these parameters. It instead would say this dot options. It would say it wouldn't even take this guy would say this dot take you this dot take you. The sooner we did this refactoring is actually better because otherwise you would end up spending a lot of time kind of if you were to match down a much stronger parts than this. That's it. Now obviously it's going to say I don't understand this because you're inside the for each. So at that point we will have to basically hold the reference of our object which is our self equals this. And then we can say pass this guy can still call these methods which are in the global scope. The next step would be to kind of bring them also underneath this guy. Let's run the test everything still passes. So one small refactoring we kind of start pulling out a view and moving this into the view, right? And these other methods which belong on the global scope we don't like that. We're going to pull those in also into this guy. So far everyone's with me the kind of approach we are taking is this too slow for you? I've done this before so it's very slow for me but I'm kind of making sure people follow in. Let's do this guy. Now only till here. So that now goes under it takes the dollar and it can do whatever it needs to do with the dollar and here. Now what do you call this? Let's actually the one thing that is very confusing in JavaScript, especially if you program in multiple languages is this whole this thing you don't know when is what. So one of the conventions I use is just right at the top call self. So then onwards I know what I'm referring to. So then I can say self dot this method that should be pretty much it to make that work. Yeah sure enough. And then the next thing we need to do is bring this guy also with an R scope. This now takes dollar and C which is cool and then here it's complaining that I can't find what you're referring to. So it's self dot this and C that's it. So that's pushed everything into a view and if you notice this is really building a bunch of, you know, what you're passing in is some kind of a comment model class. You could probably build this out as a comment object which essentially holds whatever information it needs.  So let's not jump there but I'm just kind of hinting that this is an indication that hey this come kind of a model lying out here that could be pulled out. And then I think we are in pretty good shape as far as our plugin code itself looks. Yeah. And then all the HTML portion pushed out to the view. So next thing is let's write another tests and that would make it a little bit more interesting than what we've been doing so far. So the next test I want to do is let's say you want to actually sort your comments based on the order based on the most recent one on the top. That's there's now going to be some logic that's going to start kicking in. So what do we need to do? We are saying that should display most recent comments on the top.  Now somewhere in the comment itself you will need a date thing that would say when it was posted or whatever which our server obviously knows. Our server is going to return that we're going to take that to then decide the order in which. So let's say for the purpose of this we're going to pass in a date to this guy which is last updated time. And I'm just going to pass in an ISO string which the server is going to return easiest way to remember an ISO string is to copy it from somewhere. That gives us an ISO string of 2014, June 19th, whatever doesn't matter. And so that's good. All of these guys are good here now on this object. We obviously need to first and then, oh no, what am I doing? I don't need this. I already have a comment. I now need this guy to have last updated whatever we put here except that this date probably would be a more recent date. So right now if you see the order in which it's actually displaying here, it shows the first comment and the second comment. Let's try and flip that around to see if our logic actually works. So the first comment is actually updated on 619. So let's make this 719. This is a more later comment, latest comment. Actually at this stage, I would argue that the first test is not really relevant anymore. So we could see the first test as in this particular test here that we have should display multiple comments. We're actually making it a more specific spec. So we could actually get rid of that one and make it more specific, which is should display the most recent comment on top. We've got the first comment. We've got the second comment, which is later. It should be true. And now this should be Jack while this should be run the test expected to fail because we have no logic to show it in a reverse order or whatever the latest order. So now we need to go and build that logic to show it in a certain order with me so far. So what do we need to do now? You guys are going to drive this from here. The point is, is it simple enough for someone else to jump in now and kind of take it forward, right? That's like the litmus test. Is your design simple enough? Is your design easy to understand? Can I bring someone in now and ask them to kind of take over and drive from here? That's to me an important aspect of trying to keep it simple. So I'm not going to risk that on the stage. I'll just continue doing it myself. What do we need to do now? You guys can guide me. So obviously somewhere where we are building the comments somewhere where we are basically looping over the comments. Now something needs to happen before we start looping over our comments. So we need some kind of a sort feature which is going to sort the comments based on the latest time. And then once you sort, then you simply loop over it and then you do. So it should be fairly easy to add a sort to the data. Now this is where I would say that we kind of doing something more with just the data that we have. And at this point you probably want to pull this out into some kind of a comments object and do all of that sorting functionality, other kinds of filtering functionality that we're going to add into that. But we're going to start right now here and then move it out there because you know that this works and just make it work inside the context of this. So somewhere here we basically want to sort our data based on updated date. Last updated. So what do we do? Is there a sort function? Yes. This.options.data.can I say sort and that takes a function. This is going to take a and b and it's going to sort and return you back something, right? No? I don't remember my sort so you guys have to help me. Sorry. Return a dot. Good. Last updated because it's a string right now and you want to convert it into some kind of a date, right? Because what we've passed in from the server is this. We'll keep that in mind. So let's pause on this. Where is our a? Our a is here. So let's say var first or a last updated equals. Can I say date dot parse and take a dot last updated? That's going to give me a date back, right? And I need to do the same for b dot last. So I've got these a and b. Now what can I do? Now I can. Can I directly subtract or I need to say get time or something like that? Well, we'll try. That's one of the fun of TDD is you can actually learn, right? I don't know. Let's just try because worst case is I'll run the test and I'll see it right away. So it gives me an opportunity to say, well, maybe I could just be able to subtract these guys out. Last updated. Now I am doing this wrong. So this should be a last updated and this should be b last updated. I'm not sure what the order should be. Should it be b minus a? It should be update. I have nasty names here. It's going to rename that last updated. So this sort is going to return me what? A sorted thing. Can I just then say dot for each on it? Yeah. Trying to get a little bit of field for the functional style of doing things. Sustaining them and so I don't know if this will work. Let's run. It doesn't. What does it say? It says expected blah, blah, blah. First to contain jack, but it did not contain jack. It contained nourish. So that must be our order here, our sorting order. So maybe flipping the order might just work. I don't even need the get time. That's something interesting. But you know just flipping the order. I know we're trying to get the one which is the latest on the top. So that minus the new one and that's going to give us. Let's so this is not going to change because we don't have now. That's interesting. This should have failed because we are not passing in the last whatever in the HTML. We're not passing the last updated time that ideally should have bombed here. But we can be pretty sure that the server is going to return this because that's the API of the server. So we're not going to put some checks for it. But anyway, now what we have here is is we're going to basically sorting it and then applying some kind of, you know, building appending it into each of our HTML. At this stage, you can see that there is a bunch of things that we are doing which is specific to each comment that we are getting. And we're also trying to pull out things from the comment itself. So this might be the time when you might want to create something like a function comment, which takes in C and then you can say this dot message equals C dot message. This dot user is user and then this dot last updated is date dot parse C dot last updated. And then your comment could also have a function thing on it comment dot prototype dot compare compare true. And that would basically be a function which would do something. And this logic that we wrote here. So a we don't need this parse because we've already done that now and simply we could say here now compare return. We need to take other in here. We have to say other dot last updated minus this dot last updated. Are you guys with me making that move here? And so wherever we are actually getting this C guy from that should end up becoming the object itself. So where is that? So here we will have to create an object and then simply ask the call that function. But I'm wondering where would be the right place to create that object. Because here we have simply taken all the data and passed it to the true XML method. In the true XML method or maybe much before where is our constructor right here. No, this is kind of weird you don't want your declaration at the bottom. Here we're just holding on to the options. So instead of holding on to the options how about holding on to all the comments and array of comment objects. And so this might be a good place to do the conversion. So you could simply and we're not we're not using anything else in the options right now. So we could convert this into I'm going to leave this for a minute. I'm going to say this dot comments equals. So I've got the options. I can say options dot map and I can take a funk into this. What I'm trying to do inside this map is basically take each of the object that I get converted into the object into the comment object and then store that into the comment. So what do I need to do here? Simply return. I'll have to take something here. Oh, sorry. Good point options dot data dot map. And then that should basically give me each of the object or each of the data option. And then I can simply say new comment and pass in the seat. Fair enough. That's going to give me comments and now I can work with comments instead of working with options. So let's get rid of that. And now we have to go back and see where we are actually using comments. So here this will basically become comments. Is that correct? And same thing here. It's going to become comments. And then I'm going to say comments dot sort. Do I need to say comments dot sort? Why not sort it right when I build it? Right? Why do it? Because it's not going to change once it's built. Right? So I could just sort it right there. I might need the ordering. Well, if I did, then I would store it. But in this case, at least I don't have a use case that I would require the original one. So I'm just thinking I might just sort it and keep it in the sorted order. So it just becomes easier to display. Yeah, that might be the default. You could override that by passing in an option. Like what sorting thing? Like that's something we've not really gone into. But the options thing that we provided, you could pass an option saying, do you want to show it sorted? Do you want to show it in the original order? So that's a simple option that could be passed in from your plugin. Yeah, so I could do the move the sort over here. This would get a lot cleaner down there. And there, down here, all I would have to then do is for each and then call comments dot, you know, view on that. And then I would be done. I only have seven minutes left. So I'm kind of trying to just talk through a little bit and not actually do it. But so that you see, I've got a comment now, which is really more like a model. It doesn't really have any view related logic in it is going to do some sorting. It's going to do some other functionality in there. We talked about private, which we couldn't get to. So private would be another, you know, option. Another thing that would be passed to the comment. And then the comment would decide whether this is viewable or not, depending on whether the private flag is set. So the comment itself will start doing a bunch of interesting things for us. We would have the comment view, which does all the HTML related stuff, which would probably become a lot smaller because all of this functionality would get moved into the respective places. So the only place where you will see the jQuery itself leaking into is your comment view. And then your model and other guys would not have any jQuery reference at all. Right? So if we had more time, we could obviously go on and kind of do that. I'm going to quickly jump in and I'm going to show you something that I have ready here, just so you can see what this could evolve to. Oh, we didn't even get to Ajax. Let me quickly talk about that, right? So here I have something where I can quickly show you how would you stub out an Ajax call. So let's say that, you know, we are going to pass in comments. Instead of data, we're going to pass in a URL. Right? So if we pass in a URL, we are saying this is the expected response which we were earlier passing in directly. Now we are saying that's the expected response. And that's something that we are saying, jasmine.ajax.stubrequest, this get request thing. And return, you could do 200, you could do 400, you could do different statuses, and you could just stringify your JSON and pass that in. So once you do this, the rest of it should work as normal. The one other thing you would have to do for this to work is basically you'll have to say jasmine.ajax.install and jasmine.ajax.uninstall at the end of it. If you're trying to do just this, without the Ajax stubbing out, you might run into cross domain issues and things like that because now you're trying to post something from local host to some other thing and it'll complain. So this actually gets you to work around all of those problems always because it's just going to stub out the call. So it's very simple. Like all I have to do is say jasmine.ajax.install and then I have to set jasmine.stub the URL and what response I want to return. I mean it's pretty trivial. What you also need to do which is important to remember is in your karma. Let's get this big. You will have to say jasmine.ajax. Just that little change over there and the rest of the things will work as normal. And let's quickly look at what does this guy look like after trying to do all of this stuff. And this is also available. This code that I'm showing you is also available on the same URL that I showed you on the GitHub. Just knock off the demo portion at the end in the URL and you should get this example. This is all fully checked in. So basically we have a comment. Notice we were kind of already here at this point. Now we added the private as well. The comparative method is on this. And then we also pulled out another model called comments which would basically do the map and then the sort. So the comments would hold on to all of those things. There is something called authorized. Is this user authorized to view this comment or not? And then pretty much everything else is what we have seen so far. So the other thing is that when you get JSON from the URL, if you pass in the URL, you'll essentially have to pass in a callback because otherwise your test might run through it and it might not get the result. So what you'll end up having to do from here. So if you notice this is where we were kind of going. So you have a new comments view. Then you're going to say apply comments. You're going to pass in the option and you're going to pass in a callback. So whenever it's successful or failed, the Ajax request is going to basically call the callback which is going to append whatever response you're going to give to the container. So this is the only place where we are touching the DOM or we're doing anything with the DOM. Everything above this doesn't even touch the DOM. And that's one of the things of kind of trying to make it immutable and having only side effect at the last step. Everything above this is essentially a pure function. So it doesn't do anything with the DOM. It essentially builds kind of a semi-virtual DOM and operates inside that which is easy to test, which is easy to do whatever you want to do. Plug in a different library instead of jQuery. It should still all work as normal and then pull that out as a separate thing. So yeah, I have two minutes left but that's kind of a quick run through of where this would end up going. And yeah, that's pretty much it. So I'm sorry we couldn't actually do a live demo of the Ajax thing but I hope you get the idea of how trivial it is to do Ajax stubbing out. All right, so two minutes for questions. What's the difference between spy and stub? So that's actually one of the common misconceptions that people have is they always get confused between what's spy, what's stub, what's mock, what's... So there are different kinds of fakes. So we call them generically as ways of faking something. So to me, a stub, which is what we are doing right now, so we're saying don't go to the server, stub the call out to the server and just return this particular data or JSON or whatever. So that stubbing is when I want something and I'm just going to cut that out and I'm going to return the data right away. Spying is essentially where I expect it to do something on behalf of me, like for example send out an email. So I'm going to say spy that method and just in the end I want to verify that actually did you call the method with the right parameter? Did you call send email with the right user name, with the right email address in the body? So that's spying. So you don't... One is stubbing out when you want to get some data.  Mock is you have to set the expectation beforehand while spies you don't set the expectation you just verify in the end. All right. Any other questions? Yeah. How do you estimate? That's a different topic. I have not estimated in the last eight years of my career. So you're asking the wrong person. So if they ask me to estimate, this is one of the reasons why I don't work for big companies because I don't know how to estimate. I don't think anyone knows how to estimate. Everyone's just throwing a dice and throwing a number out there. So that's the honest answer. How do you estimate? No, throw a dice and pick up a number. Because if I would have done the similar plugin ten times before, yes, I know how long it's going to take and I can give you an estimate. But you know what? I've never done this before. And I don't know. I can give you a guess, but the problem with giving guesses is then you get held accountable for giving a guess. And that's a very dicey position to be in. All right. Last question. This goes back to Dan North and all of his... So Dan North is a person who coined the term behavior-driven development. And his point is that when you use the word test-driven development, people think about it as a thing about testing. But as you saw, this is not so much about testing. This is more about driving the design and flushing out the behavior of what you want. Right? The point is that the terminology test-driven development makes people think that this is about testing. So he kind of coined a new terminology called behavior-driven development, which confuses the heck out of people, saying, what's behavior? What is test? It's just that test-driven development had the test connotation, so behavior-driven is better. Now, I have a paper that I had written which basically goes into more details about talking about different styles of doing test-driven development. In the paper, if you look up as aftars of test-driven development, you will find that I list a whole bunch of different styles. So behavior-driven development kind of fits into the outside-in way of doing test-driven development, which basically means that we're going to look from the business perspective, from the user's perspective, and kind of drive the system from outside-in. You know, are we building the right product? Two, are we building the product right? Kind of a thing. When you're doing more of the traditional what people think of test-driven development, they kind of flush out the system inside out. So you might start with the core of your system and start flushing it out. Behavior-driven development also kind of has become more of a methodology now in some sense, where it talks about how collaboration should happen between people and all of that stuff. So I think it's kind of getting bigger than what the original intent was. But to your question, outside-in or inside-out? All right. All right, thank you very much. Hope you had something to learn from it. Hope you had something to learn from it.


The name of the exercise is Hurricane Noah and we're experiencing a passing hurricane with tropical storm force winds and flooding has beginning to occur in our community. The Sheriff's Office just wants to reinforce the emergency management's message to shelter in place. We do not need any unnecessary movement along the roadways especially when they're flooded. If you go out into the roadways emergency responders may or may not be able to get to you and in fact if we have to get to you you may be putting us in jeopardy unnecessarily. We are going through our comprehensive emergency management plan and lessons learned from both Matthew and Irma that we experienced the last two years. So we are working through some issues with bridges, sheltering issues, transportation, debris. So we're bringing all those to the forefront during the exercise forced to work through those issues as a team in a no fault environment.


So hello, everyone again. So I write in Rust today. And at night, I'm thinking about how to bring P2P networks and web closer together. And today, I want to talk about WebRTC. WebRTC is an HTML5 technology that's been available since at least year 2012. And it's currently stabilized as a standard. But it's not currently stabilized as a standard, but it's already available as a draft. And it's usable today. It's not, this won't be a talk about intricate technical details of WebRTC. And this talk is not only about WebRTC per se. It's about what's possible and what changes WebRTC might bring. And at first, I thought about, to give you more practical examples, and about more details about the structure of the centralized networks. But then I thought that technology in isolation is not that important. Because every technology serves a purpose. We don't make things just to make things usually, right? So I want to give you a broader perspective on this technology. And because I strongly believe that WebRTC has a very big potential to change the world, and spark a new decentralization revolution. And I want to inspire you to take action and participate in that revolution and help to build the new internet. But you might ask, do we actually need that revolution? Why do we need to build the new internet while currently it works quite perfectly? Well, to answer this question, we need to get back in time a little bit. In the past, we had a dream of a completely decentralized network, not controllable by any authority, and not prone to censorship. A network where every individual has freedom to say what they think and what they want. And that network already exists. Today, we know it has modern internet and web. However, this is not the same internet as it was originally. In the past, we didn't depend on large corporations running giant data centers and providing, say, email services. The internet was small and simple. And at first, people run their own email servers. Then, in the late 90s, there were multiple email service providers. And because it's just not too easy to run your own mail server, right? It's easier to just register on someone else's computer and make it their headache to deal with the administration tasks. And nowadays, our email usage is consolidated around just a few of big providers. And how many people today are running their own email servers? Raise your hands. Well, actually, I see just a couple of hands and it's quite expected. And notice that this is a technical audience. And I think it's sufficiently safe to extrapolate and say that almost no one from the general public use their own email service now. But the email protocol itself is still inherently federated, decentralized, and open. And many of the original internet protocols were built in that way. It used to be IRC, FTP, HTTP. All of these protocols were created more than 20 years ago with the vision of open internet of equal peers with equal power. And we had a concept of homepages which belonged to users. And now we have Facebook profiles which belong to Facebook. It's just that in the name of convenience, we have sacrificed our privacy and control and handed them over to third parties. And the internet landscape has changed drastically. Now we depend on centralized services to do everyday things. We upload our files to Dropbox to share them, which are on Facebook, which are on WhatsApp, and we pay with PayPal. These services are perfect. They're great. They're easy to use. And this approach to technology helped to bring a billion of new users to internet and will help to bring many more. But at the same time, this approach has a downside. It makes it even more easier for governments to track all your communications and snoop without many hurdles. And they do that with good intentions, actually. They do that to protect you and children. But I think that it's the wrong direction because almost all of our data and almost all of our messages can be read by special government agencies, and we have allowed them to do that. And many of us know where this can lead. The government incorporate control, and they all seem wise big brother who knows for us and better than us what we can read and what we can write. It leads to censorship. And this is not some kind of theoretical problem. Our reality already in countries like Turkey, for instance, where they block Wikipedia, or in countries like China, where they have more than 3,000 websites are blocked already. But the problem is actually bigger than that. Our news feeds are controlled by Facebook and Google. And the news feed creation algorithm is in a packed black box. And for all we know, it just shows news that are similar to the ones you liked before and hides the news you supposedly won't like. And this algorithm alone has significant power to skew election results, for instance. Or in simple words, just this. Well, should it always be like that, though? I think not. We can fight back by creating decentralized apps that are easy to use. And I personally believe that this is critical and crucial because the user experience is just as important as privacy because no one wants to use bad apps. And no one wants to use apps that are hard to understand. We have seen that on the example of PGP. And regardless of all technical merits of PGP, it's just too inconvenient for everyday use, right? So we don't even use encryption for our email now. So we need to incentivize users to defy the status quo and go fully decentralized. But how can we do this? I believe that WebRTC can be the answer here. It's already available in Chrome and Firefox on both desktop and mobile platforms. It doesn't need any plugins or any installed software to work. It just works. You open a web page in your web browser, and you can connect directly to other browsers without passing your data through intermediary servers. And WebRTC is getting quite popular lately, but there are still many misconceptions about it. First, there is a common misconception that the WebRTC protocol can be used only for media. It runs for voice, video, and so on. But actually, it can do much more than that. Media is certainly one of the most important applications of WebRTC in the today's web. But it can be used also to transfer any text or binary data between connected peers. There is another misconception about WebRTC. That it's suitable only for the web and can be used only from web browsers. But in fact, you can use the protocol from anywhere. And it's a very powerful idea. Because it means that we can create WebRTC applications for desktop or for internet of things. And they will be compatible with web browsers, allowing to communicate in both directions. And WebRTC can play a significant role in the recent trend of redescentralization or bringing back the internet to its origins. And today, we witness a kind of renaissance of decentralized technologies that was started with Bitcoin. And many millions of people use these technologies every day. And I believe that it's very important because it shows that decentralized networks are possible at scale, and they are valuable. So WebRTC can serve as a kind of a bridge to existing peer-to-peer networks and can help in creating new ones. And the most important thing that you need to know about WebRTC is that it's simple to use. There is a concept that is called data channels. And the data channels provide essentially the same API as WebSocket. So first, you just initialize a data channel. And that is a kind of a data stream between two peers. Then you can set a hook to handle incoming messages. And then you can send a message yourself. And that's basically it. You don't need to worry about security or data transfer, because when you establish a connection between peers, it automatically initializes the session encryption keys. So data encryption is mandatory in WebRTC, so memory can't tap into your communications. You just need to make sure that you transfer the session information securely, and you do that with signaling. With the signaling here, you exchange the connection information between peers. And this is a complex topic, worthy of another 30 minutes talk, but basically it's just a setup stage when peers choose some point to exchange the connection information, which includes IP addresses and encryption keys. There is a caveat though. That point of exchange can be considered a single point of failure or some kind of centralization point that defeats the purpose of WebRTC, right? But it certainly can fail, but it's not more centralized than, say, DNS, because DNS can fail too. But if you know an IP address of a server that you want to connect to, you can just use it effectively by passing centralized name servers. And it's basically the same with WebRTC. You can exchange this information out of that. This is, that is, you can just email it or share it in some secure chat, or just send it with DHL or snail mail. Doesn't matter. When your counterpart gets it, you don't need any servers anymore, and you can talk directly. And this part, signaling, is not defined by the WebRTC standard, so you have to invert your own way to discover peers. And this gives you greater freedom in choosing the most efficient way to do that. And that is usually done by using the WebSocket connections, but actually you can just use anything you want. And now that we know the basics, we can try to establish a new WebRTC connection. It is a bit more complicated task because it can build different network topologies. You can just connect two peers between themselves, or you can build complex peer-to-peer networks. And on top of that, the connection process would be kind of different for each party. There are two sides of the handshake process. The connection initiator and the recipient. On this slide, you see the basics, the basic step required from an initiator. You create an offer, which includes a session encryption key, and set it as a local description. On the other end, when through the signaling channel, you get a request to initiate a new connection, you follow almost the same steps. This time, you set the remote description, telling the peer object that someone wants to initiate a new connection. Then you create an answer to the offer and set it through the same signaling channel so that the initiator can get it. And finally, when the initiator gets an answer, it just sets it as a remote description. And that's it. We have established a peer-to-peer connection between two browsers. Now we can probably use that deliciously simple data channel API. Well, never mind, because that's how it would work in some wonderful imaginary world in which we don't live, fortunately. In the real world, we have to deal with another problem. We have to deal with nuts, the cornerstone of peer-to-peer communications. Because the IP version for address space is limited and because people want you to feel more secure, network address translators were invented. And as you know, nuts translate IP addresses from your local network to the global IP addresses. And there is a wide variety of types of nuts. Symmetric nuts, port restricted nuts, full column nuts, and so on. And the bad news is that you have to deal with various types of nuts with different techniques. But the good news is that these techniques are pretty well known. And WebRTC takes care of that for us. So all we need to do is to provide known stunt servers to gather your public IP address. And then you need to send it along with the rest of connection information through the signaling channel. And basically, stunt works just as a mirror. You send a request from your local network, but the stunt server sees your translated address. And then it just returns that translated address and you get it to peers through the signaling channel. There are some cases, though, when that's not completely possible to connect directly, such as when both peers are behind a symmetric net. And the solution here would be a turn. The turn is a kind of a last resort because it basically works as a proxy server. Both peers connect to the turn server and then it just relates traffic from one peer to another. And obviously, it's a costly solution and it's not readily available as opposed to stunt, for which we have multiple public services. Running public turn server would be very expensive, but theoretically, we can reuse the existing peer-to-peer networks, such as Tor, to relay traffic through the existing nodes. But for now, it's not quite possible, so we have to deal with, so we have to set up our own turn server, perhaps. But fortunately, turn is needed only in minority of cases, so usually, we don't need to deal with it then. And to make our life simpler, Weber-TC uses the ICE protocol, which employs both stun and turn to establish a connection. ICE helps to gather candidates which are basically hand the thought of as pairs of IP addresses and ports. So we pass these addresses and ports to our peers, so that they can connect to us. And actually, there is a great feature in ICE that it also collects your local IP address. So if we are in a local network and we want to connect to our local peers in our LAN, we don't need to go through the Internet connection to do that. And the Weber-TC implementation of the ICE protocol allows us to concentrate on the application side because it does everything for us, so we don't need to do much to set up the connection. Basically, what we need to do is to provide the stun and turn server addresses and then set it as an event hook to gather our candidates. Then we send that information through the signaling channel. And on the other end, our peers gets that information and calls the add-ice candidate function. And essentially, that's almost all we need to do, all we need to know about setting up a basic library connection. However, what we have seen so far is the most basic topology because it connects just to peers. Well, it can be seen as a kind of peer-to-peer network as well, but it consists only of two actors. And it's fine for your cases when you just want to connect to peers to have kind of a chat or something like that, but very often we would need more than that. And for multiple peers, there are many ways to structure your PDB network. You can just create connections between each and every peer, but it won't be the most efficient way to do that because in case of significant traffic, the peers would have to duplicate it for each connection. So if you are aiming for even, say, at least 100 peers, the full mesh topology wouldn't be like, would require too much CPU power and network traffic. To alleviate this, we have a structuring pattern called start topology. And in this case, we choose one or more peers which have the most processing power. These peers serves as a kind of a multiplexer, effectively relaying traffic. So it acts as a proxy again. It works, it's efficient, and Google use it for their Hangouts implementation, but it has an obvious disadvantage. It's centralized, and now everyone relies on a single point of failure. Fortunately, there are many other alternative ways to structure PDB networks. One of the examples would be onion routing in Tor that builds chains from randomly selected peers. They interlace traffic through the build chain, encrypting the data at each step. So it becomes practically impossible to tell whether that traffic was related from some other node or if it is the origin of the traffic, if it is a original center. So we can't know who is the center. Or using distributed hash tables, we can structure networks as binary trees or rings. This is what the cadamely algorithm does. The cadamely algorithm is a base for the bit-oriented DHT implementation. It gives each peer a unique randomly selected node ID. And each node has its own routing table, so it knows about other nodes which in turn know about other nodes themselves, so you can imagine as a kind of a tree. And then when you want to store something on the network, you hash your content and that will be your key. DHT maps those keys, which are hashes to node IDs which can be thought of as hashes as well. So having some content, you would already know on which node you should store it. And you can reach that node by sending a request to a node that from your routing table that is the closest to the node that you're looking for. And then that node that is close to you checks its routing table and repeats the steps. That way, in multiple hops, your request will eventually reach the destination and your content will be stored on the network. But while the details of these algorithms are complex, so we'll skip them for now. And for the moment, let's concentrate on bit-oriented. Many of us use bit-oriented at least once. It unloads Linux ASOS. And at first, the bit-oriented protocol depended on centralized trackers to find the connection info and IP addresses of peers that have certain files. And now with the introduction of DHT, it just needs to find a single peer to be strapped from and this is usually done by contacting a well-known node and then it can continue to work in a decentralized fashion. But again, as with signaling, this is not a point of failure on centralization because if you know an IP address of at least a single peer, you can join the network. And now what will happen if we combine bit-oriented with WebRTC? We get web-oriented. It's basically a bit-oriented limitation in WebRTC terms that can work in browsers. It can't communicate with bit-oriented peers directly because they use different network protocols and you can't use UDP in WebRTC connections yet so it's implemented in SCTP terms. So if you want to connect with bit-oriented peers, you would have to go through the proxy world but we don't actually need bit-oriented peers anyway. We can do a lot of interesting things just like that. WebTorrent simplifies interaction with WebRTC even further and it can be a pretty straightforward API. You can send a file or a JavaScript string or a binary buffer and it will be automatically converted into a torrent file and that torrent file will be published and announced on the network behind the schemes. And other peers, knowing the torrent hash, can download the file and send it further and the WebTorrent API is very simple. We have seen almost all of it on these slides. It's also available for Node.js as well so you can use the very same API to build server-side apps that can talk to browsers using the WebRTC protocols. And files are actually not limited to those Linux ASOs. Basically, everything can be represented as a file and there are many practical applications for WebTorrent today. For instance, we can build a distributed GitHub. There is a proof-of-concept project called GitTorrent that is already working and with that approach, you won't even need to depend on GitHub availability to get your sources and Git will be truly decentralized. And another application that is practical today is content delivery. You can make your website a CDN and visitors will help to distribute your content of your website to other visitors or you can even make your website torrent file itself represent your website as a bunch of files that will be served by WebTorrent. Actually, there are multiple possibilities and ideas. However, WebRTC is an imperfect technology. It still needs to come a long way to support large-scale networks that can replace or improve the current state of web. It's not perfect and has many limitations. The browser support is not perfect and current modern web browsers such as Chrome or Firefox limit a number of connections that you can establish and this hinders the ability to build DHTs in the web browsers. And for now, it's quite unfeasible to implement the contemporary DHT algorithm on top of WebRTC because of these limitations and because of the handshake we had. And that means that WebTorrent library currently depends on trackers so it's sort of centralized for now. Another important issue there is that the browser sessions are short-lived. When you close your tab, you will lose all connections and the next time you will have to go again through the handshake process and the signaling and so on. This problem kind of can be fixed by allowing to run WebRTC sessions and service workers so that even if you close your tab, you will still remain connected to your peers. But it's not available today. Unfortunately, that's not implemented in the current WebRTC standard, but there is a tracking mission in WebRTC repository on GitHub. Another possible solution to that problem of short-lived sessions is hybrid servers because as you remember, WebRTC is not limited to browsers only so we can integrate the WebRTC protocol into existing P2P networks and other existing peers can serve as intermediaries meaning they can talk to peers that connect through the WebRTC protocols so WebRTC users can be just kind of clients and the server-side peers can serve as a backbone and that won't be a centralized network because the server-side clients are just the same peers, they're only, they're not limited by the browser. Still, while there are many problems to overcome, WebRTC is very promising. But peer-to-peer networks have a set of problems of their own because these networks are trustless, it's hard to solve the problem of malicious nodes or spam and if we store content and multiple nodes, we step into the territory of distributed systems which are very hard to grasp. So apart from the problem of spam and malicious nodes, we have to deal with consistency and churn as well because what will happen if all nodes that store some file on the network leave all at once? You lose access to that file and if that file is your Bitcoin wallet for sale, it will be very sad to lose it. So for redundancy, we need to make sure to have enough copies of the same file distributed over multiple nodes and of course, we should not forget about encryption as well because in trustless networks, basically anyone can read your files and most importantly, we need to make sure that these nodes are incentivized to stay meaning that it should be in their interest to share these files as long as possible. And speaking of incentives, I personally think that the economy of P2P networks is not less important than their algorithms because who would want to share their bandwidth and computer resources if there is nothing for them, right? Bitcoin kind of solved that problem by giving some coins to the nodes that are do mining. So to build large-scale networks, we need to find a way to reward users. And this problem is tricky because it can lead to centralization all over again. Remember that the modern web originally started as a distributed network, but the problem is that economy incentives and the question of who provides their sources lead us to the modern days of giant data centers and mega corporations.  So we need to find a good way to overcome this because it would worth it. We can bring existing P2P networks such as store, such as store, Bitcoin or Ethereum to web by porting them using web assembly and adding the Weber RTC protocol support. However, that won't be quite possible for now because European TCP are not directly available in Weber RTC yet. However, they might be available in future. In the meantime, we can build new P2P networks and there are many, many ways to utilize them for the good of humanity because such networks are more secure and resilient as the example of Bitcoin and Bitcoin shows. It is especially important in such applications as Internet of Things, which is becoming our reality already. And we see that medical devices, self-driving cars and critical infrastructure already depend on Internet, which is by and large is controlled by a few of big players now. So I strongly believe that we should not give this micro-operations even more power. And thanks a lot for your attention and bringing it to answer your questions. So I have a few questions for you. Sure. Are there any examples of great web RTC websites which are purely decentralized apps? Well, this field is currently experimental and the projects that use Weber RTC are currently experimental as well, but I can name a few. Probably there are websites that replicate the Spotify or goal music functionality by basically creating a peer-to-peer network where you can share your music with a convenient interface. So basically, from the user's experience point of view, it's not different from Spotify, but underneath it uses Weber RTC to share the music among the peers. So it can be shut down or it can be controlled. The music is your own and you can share your music with your peers. Well, probably there are many other experimental projects, but I don't quite know about them yet, but we can build them. So that's the point of my talks, to incentivize, to inspire you to build these applications because there are quite many possibilities to build these apps. We can make Internet more secure by, for instance, by replicating the Tor functionality on top of Weber RTC and making it like uncensorable and private so that CIA and FBI can't snoop our communications. Awesome. How should we approach dealing with unethical content in a decentralized network since it's uncensorable? Well, that's a tough question because we need to, there are many possible answers to this question and government would certainly want you to, to that single answer is to prohibit the decentralized networks and make all centralized and controllable, but I personally believe that we should take this question out of technical realm and answer it in another way. So probably we need to educate people and just we can deal with the content that is questionable without also creating a possibility to censor content that is not questionable because in democratic European countries, the questionable content is like we all know what it is, but in some other countries that are not so democratic, this questionable content can be, for example, critic of government or something like that and they can censor that with a good intentions again. So it's a tough questions. We can't deal with that in a single way. So we have to, probably we have to allow all content on the decentralized networks. We just need to educate people to like, to make them not interested in that questionable content. Thank you. Very well put. How would we store data that we need to restore, for example, a Slack conversation when data only flows P2P? Well, if we are, if we are speaking about whatever to see in the browser, probably we can store that data through the W3C APIs. We have, if I remember correctly, there are new APIs now available in HTML5s, HTML5 that allow to store files on your local file system. But apart from that, there is a local storage and session storage that we can use to store the intermediate information, the information that would not require to go to the file system to be stored. So like, probably messages or emails can be stored in the local store and we don't need to go to the local file system. Nice. And the other possible answer is that hybrid scheme. So we can probably create server-side applications that would use the WebRTC protocol and these server-side applications would talk to the client peers that are working web browsers. So web browsers would just use the infrastructure that is provided by the server-side peers, but again, there is a question of incentives. So what is there for the server-side apps to store your content? It's an open question. Nice. How might you scale this for tons of users all communicating on the network at once? Well, the peer-to-peer networks are inherently scalable because the more peers you have, the more users you have in your network, the more efficient it will be because it will be, if you have, say, million of peers, your content will be scaled all over the globe. So it will be even faster for you to access this content because probably for some popular content you will be accessing your local nodes that are in your local network or in your country, for instance. So peer-replicate content all over the globe, it will be even more efficient than the current infrastructure. But with WebRTC, the problem is that currently, web browsers limit the number of connection to 150 or something like that so we can build decentralized networks at massive scale for now. But hopefully, and I hope that this problem will be solved and the browsers will be allowed to connect to more peers. Awesome, thank you so much, Nikita. Thank you all. Thank you all.