 Well welcome. It's great to see so many people here again this year even though I can't actually see you. I'm imagining that you're all out there. So this year we're going to release Rails 5. I love people clapping for what they don't actually know what they're gonna get. We'll see whether you're clapping at the end. So Rails 5 is, as the number suggests, the fifth major release of Ruby on Rails in 10 years. We have released a major version of Rails every two years since 2005. I started working on Rails in 2003 and it took us about two years to get to 1.0 and then somehow magically as clockwork we've managed to push out a release every every two years. So I think maybe last year we kind of looked at the release schedule and said oh we've been releasing a major version every two years. Let's just say that that's that that was the plan. We're on a two-year schedule. I love yesterday's weather. It's so much easier to predict. But there's also something funky about 5. I don't know why this. I don't know why certain numbers feel special but it feels like a milestone. Maybe it's because it's sort of 10 years of major releases or whatever it is but when I started thinking about what I wanted to talk about at this Rails Conf which I think is like the eighth or the ninth. I don't remember. I think 2006 was when we started with Rails Conf. I sort of had this question of thinking about why. And particularly sort of a personal why. Why am I still doing this? Like it's been 12 years. It's been the majority of my adult working life. I've spent building Ruby on Rails and products with it. Why? Like why am I still here? So that question sort of goes to to the root of something I find so interesting about software which is software is about people. And people are about motivations. What drives them? What are their values and where they come from? And I think if you understand that you have a much better chance of understanding sort of the software that comes out of that. Sort of peeking behind the curtain and looking back there and see like where's all this stuff coming from? And I've spent a lot of time and often try to sort of do that to other software projects. Like I look at a piece of software and I just be fascinated. How did you arrive here? Like how did you amass in the early days 2,000 lines of XML configuration? Like what went into that process? I'm just fascinated. I want to understand. Truly. And that process I've mostly used to comedic effect and sort of poking at other communities and frameworks or whatever. So I thought on this sort of fifth major release I should sort of point it in words too. And look at my own motivation and why I'm still doing this stuff. And what is it that actually drives me to do this? And there's some obvious answers. There's not just one answer as with just about anything. One of the reasons obviously is I love the community. I love what we have here. I love the interaction that I have almost on a daily basis in GitHub pull requests and on the mailing list or on Twitter or Campfire or any of the channels that we have to interact. And that's a lot of fun. But that's not the whole reason. Like I have other communities I'm involved with and they're fun too. And I didn't necessarily spend 12 years pouring in tons and tons of my time into that. So that can't be a fulfilling wholesale argument to that. Another argument which is sort of the one I usually go to is the sort of hedonic motivation of just I just enjoy this. This is a pleasure to do. Writing Ruby code is a privilege and a pleasure and I really enjoy doing it. So that's a reason enough in itself. And I think that's very compelling. But there's also other things I like doing. And there's again other things where I don't pour it in that much time. So as I sort of dug deeper and deeper in the introspection on why it is that I'm still here, I came to something sort of a little more primal perhaps. And that's sort of been part of the switching motivations I guess that's been happening over the years for me. When I started out with Rails it was it was hedonic. I just enjoyed doing Ruby and it was sort of necessity. I needed to build Rails to build Basecamp in Ruby back in the day. But over time those two things sort of one became a little bit of a routine and the other thing became not really necessary anymore. Like now I work with a bunch of great programmers at Basecamp and I don't necessarily need to do everything myself. But as that was happening, I also started to accumulate stuff. And the accumulation of stuff to me has this sort of that's great. It's great to build a company. It's great to build a popular product. It's great to use Rails to do all these things. But the dark side of that to me at least is it comes with this invitation to a fear, to a growing fear that all of a sudden you have something to lose. And if there's one thing I absolutely fucking hate, it's that nagging sensation of having something to lose. Because to me that's one of the prime drivers of fear. And fear is one of the prime drivers of all sorts of bad decisions. All sorts of short-sighted, conservative thinking that's about defending stuff. And I've been constantly that because I've watched that happen to other people I know or observed and other companies. And what happened to companies and people when they have something to lose. I talked about this a bit in the 2012 keynote about progress. So I kind of developed this meta fear, the fear of the fear of losing something. And I kind of decided, or kind of through inspection arrived that the fact that I've decided that I was not going to succumb to that. One of the sort of great discoveries for me personally over the last couple of years have been sort of reading about stoicism. And stoicism is all about finding the tranquility in your life and sort of contentness and say happiness by eradicating that fear, by eradicating fears of all kinds. And the way to do that is to address them head on and actually invite them in and sort of have a look. And one of those fears I was just saying was this fear of somehow waking up and it was all gone. Like all the stuff that I spent the last 10 years building gone, something terribly happened either through my own screw ups or force majeure or meteorite hit a data center and base cam was wiped out and all these sort of whatever bad thing you could imagine that that would happen right. It's not necessarily because you're thinking sort of directly about these things as you're sensing this fear, but it's there. And that's where sort of this notion of like today I worked with 47 wonderful people at base camp and and I enjoy that so much. And I'm always talking about like, Oh, the longevity of this. Oh, it's great to have worked with these people for 10 years and so on. And again, in that I'm building up this something to lose. Right. So if I'm going to tackle this personal fear of mine, that all of a sudden, it's gone. And I'm just left all alone again. Right. If I'm going to tackle that. Well, first, I'm going to sort of accept it. And like that could happen. Like that could totally happen. I people all the time thinking, Oh, yeah, this is just going to the gravy train is going to continue forever. And that's going to be wonderful. And I'm going to live happily ever after. And then something happened. And they don't write. So I kind of developed this mentality that if I'm going to address the fear that I could be left alone in this world, just me, I had to become a prepper. I had to become self sufficient enough that if calamity struck, I had my backpack and was locked and loaded and ready to go. Once more, just just me, just like 2003, you're left to your own devices, and you got to figure this shit out. That's what rails is to me. It's my prepper backpack. It's where I put all this stuff that I'm like, Yeah, if the world is going to end and the zombie apocalypse is going to arrive, I damn well better have my shotgun, or my turbo links, or my active support, or my active record, and they'll be locked and loaded, and I'll be ready. But sort of the prepper mindset, which I really find fascinating. I read this interview a while back with with a series of preppers. And I thought it's so easy to look at that and laugh. Like, dude, the zombie apocalypse is not actually gonna happen. You do know that, right? But that's not really what's about fears often this irrational thing. And tons of people walk around their entire life with all these fears bottled up, and they never address them, they never verbalize them. Here's a group of people who willing to say I fear the zombie apocalypse, or nuclear fallout, or do earth is going to end in some way, and I'm going to be ready. That's commendable. You're addressing your own personal fear head on, and trying to tackle that. Good for you. The one thing perhaps a place where I just agree is that that preppers, at least as perhaps stereotypically aligned, like, they're happy with this, like that shed, like, I have my shotgun, and I have my dried fruits and my can vegetables, and my shed, and then I'm set. I'm like, yeah, I'd actually kind of fear that like that's not my idea of sort of salvation. So on the other hand, like, not like I'm greedy, like, doesn't have to be that my backpack is good enough that I can build the tallest building in the world, most luxurious thing and I can live there ever after in some little island in the Middle East. I just want to be able to recreate things to a good state. Like if I can just build my own little personal house again, and it could be a place where I would love living once more, that'd be wonderful. Like that's a sort of modest, at least in my view of the world, approachable goal that I can have something to aspire to, but not so unrealistic as to like, that's never going to fucking happen. Because that sort of shatters the illusion, because this is all an illusion anyway, right? Hopefully, that I'm preparing for this sort of doomsday that I just want to be able to to not recreate internet scale, web scale, like, somebody else can do the seven star hotel of web scale internet scale. I just want to be able to create one of these things again, which is really what the backpack of rails is all about and all tuned towards this sort of middle successful, but middle tier of companies of applications. Again, something that sort of stretch goal, yes, but theoretically attainable versus at least to me, like it's not theoretically attainable that I'm going to as a single person build Google, right? Like that. That's not going to that doesn't work for this illusion. I'm dreaming up for myself. What I want is a fighting chance. Like, I'm not going to just sort of go down and fall over to my fears and let that eat it up. I want to fighting chance. And I want that backpack to be ready and packed. And I want to feel good about it. And I want to feel good about where I can go with it. Okay. So that's sort of the value. This ideal of self reliance, that that should be possible, that somebody today should be able to pick up this backpack that I've assembled for myself that I feel good about, they can take the backpack. And as one person, they can have a fighting chance. I don't actually care about building software for sort of teams of hundreds. Like that's not what fires me up. That's not what gets me passionate about open source is not what gets me excited about doing another 12 years of pull requests and arguments about the bike shed. What fires me up is about that one person that is starting out from scratch with nothing, everything either ended or they just begun. And they have a fighting chance. So if that's the value, the key principle that I am choosing to derive from this sort of what is the actual approach like this is also a little fussy, hazy, guiding motivation stuff. But what does that actually mean? What does that actually do? What does that actually lead? For me, it leads through integrated systems. This is how I feel that there's a chance to have a fighting chance that I'm not going to compete. If I'm going to use an architecture and approach to software development that requires me to build all these separate individual entities that are sort of optimized for being very neat and nice to cut off and separate and perhaps have a whole team around. That's not what's going to do it. That's not what should be in the backpack. The backpack should be aimed towards the integrated system. What do I mean by integrated system? So through working on base camp for a decade, things sort of grew a bit from just being a website, right? Like today, we have to not only make websites, we have to make more websites for smaller devices, we have to make apps for small devices, we have to have all these outlets for the application to be able to make the kind of nice little house apps as I was talking about, a nice little base camp, a nice little GitHub, a nice little Shopify. And if you want to do that through, obviously, there's tons of ways to do that, right? A very common way is just to say, like, okay, well, we're going to have the website, that's one thing. We've got to build that whole thing. And we're going to start one more time, and then we're going to build a whole other thing. We're going to build an iOS app, okay? We need to figure out all that out, build all that from scratch. Oh, shit, Android. Fuck. I hadn't thought about that. Let's build that too. Need another sort of team around that. It was like, oh, damn it, iPad, slight different dimensions, got to build a whole new thing for that too. That's not a stretch goal to me. That is just an unclimbable mountain. Like, that's not going to happen on my own. I can't dilute myself into thinking that I could build all these things from scratch on my own. So I come back to what can I build? I can build one system and I can make it damn good, and I can make it versatile, and I can make it do all these things very well and good enough. Which sounds like sort of an Aaron Patterson thing, like adequate software, it is. Adequate. Which is fine. I'm actually a big supporter of adequate software. And as I think about this, as sort of, I'm going through, I'm thinking about, so what does integrated systems mean? I love this quote, not quote, law. Every quote is sort of worthy of something and stuff for development. It has to be a law. I don't think this is actually a law. I think it's just a nice quote. But organizations with design systems are constrained to produce the signs which are copies of the communication structures of the organizations. I usually use this quote to deride and poke fun of overly complex, enterprisey, SOA, architectures of sprawling mess, as suburbia. But it can also be pointed inwards and describe why Rails is the way it is, because the organization structure of self-sufficiency and self-reliance is the number one. Right? So if that's the key thing you're optimizing for, you're optimizing very differently than if you're optimizing for building software completed by hundreds of people. And sort of that's sort of the philosophical angle of it. And if it was just that, I wouldn't be so bullish on the point. There's also the practical angle of it. Think about maybe five years ago, we were playing with what's now come to be known as microservices with Basecamp. We came up with this feature, like basically a text document inside of Basecamp. And we wanted to use that feature in multiple apps. And we were like, I thought, that's a microservice. Fantastic. Now I finally have a chance to sprinkle HTTP out over everything, and it's going to be great. So we put it, first made it as a standalone app called writeboard.com, then put it into Basecamp and you're like, yeah. Then put it into, to backpack another product we have at the time. And I was like, triple, yeah. Like this now worked three times. This is wonderful, right? Until sort of, like that was the party. And then came the hangover. The hangover was sort of trying to operate this, keep this thing in sync, dealing with the dependencies between three different apps, moving at three different paces. And the hangover was not as fun as the party. Like it rarely is. But that was sort of part of what, you have these sort of moments in your career, in your life perhaps that sort of cut a scar and then help direct you of like, I'm not going to do that again. And you could just say, well, that was just one case and maybe you were just stupid and did it in a poor way or you didn't have the tools that we have now and it'll be wonderful. No, I don't think that's the case. Which is very easy for me to say. It's actually very easy for me to say anything because you guys can't respond. So I can just keep talking and making proclamations of it which is really what I enjoy to do. So this whole format is suiting me uniquely well. And aside. But then I sort of, I came, or I didn't come up with, I chose this notion of integrated systems because that sounds cool. Like that sounds great. And you're like, yeah, integrated systems, like things working together and like the design to sort of have some knowledge of each other. And the flip side or the negative term for this damn same thing is monolith, right? Like that's the term of derision that people usually use to talk about things they think are sort of too big. And monolith usually implies that sort of there's no cohesion and there's all coupling. I don't even know how to pronounce that word. And that's sort of, that's a straw man or the argument for it, right? Like that monoliths are just poor software design. They're just a big ball of spaghetti mud. I think this actually looks, I don't think that looks anything like a big ball of spaghetti mud. I think that looks majestic. I think monoliths are fucking awesome. I think they're really cool. But I'm also sort of accepting that the word has now been tarnished and damaged. So we're going to rebrand it. That's what we usually do in the software industry. Whenever something is sort of tarnished and worn out, we just slap a new name on it, sell the same damn thing and you're going to love it. Integrated systems. That's where it's at. And I think this comes back to what I talked about last year, which is as an industry we're constantly searching for this recipe. This recipe that's going to tell us exactly the right dose of this thing and that thing and this is how you make delicious software. If I can just follow the recipe, if I can just find the magic recipe, then everything's going to be wonderful. So when you look at a sort of whatever software project you're on right now and you're like, Jesus, this is a monolith. And you say that with derision and you sort of, this is what you really mean is that this is just bad software, right? Like your fucking monolith doesn't look like this. If it looked like this, you wouldn't be complaining because that is a majestic monolith. And I really, I like how architect Clippy put it best. I see you have a poorly structured monolith. Would you like me to convert it into a poorly structured set of microservices? Which really gets to the core about all this, which is that you just have crappy software, right? But that kind of sucks to admit that you just have crappy software. So if you could just come up with an excuse, you can eradicate the fear that it was somehow your circumstances or your ineptitude or your lack of experience or your just bad ideas. And I should know because I've had plenty of all of that that took you in a poor direction and you ended up with bad software. And it wasn't because you made one application and it's not going to get better because you make 10 applications. Okay. So I kind of somehow get a little carried away sometimes and get kind of fired up about integrated software. But at the same time, if that's what you want to do, if that floats your boat, fantastic. Rails 5, the mother of frameworks for microservices. If you want to use Rails to create that setup and have a lot of different things that sort of derive off one API base and it's really neat and structured, that's wonderful. We're going to bag it into Rails 5 and you're going to love it on day five and you're going to hate it on day year two. But that's all good because in the meantime, you won't be blaming me and we can still work together. I think that's the other, that's the thing I really love about the Ruby and the Rails community is that even if we feel so passionate about certain things, and I feel really passionate about the majestic monoliths and integrated software and how wonderful it is to pack your prepper backpack, I can also think, well, that's fine, but if somebody wants to collaborate on Active Record, I don't give a hoot which deity they choose to pray to at night, whether that is the alter of microservices or the one true monolith. We can still work together and it can still be wonderful and we can still progress and that's great. So Rails 5, we're going to have a slimmed down version of the base default when you want to start just an API app that doesn't have any views, it doesn't have anything else, can be used as a back end for client side MVC. It can be used as sort of any sort of thing and we can collaborate on all these other tools and frameworks where that's all shared and that's wonderful. I'm going to tell you a little secret, that is not the feature necessarily of Rails 5 that I'm personally most excited about, so let me get to those. And now, sort of at least for some people in the audience, they're going to think, he's trolling now, isn't he? Turbolings 3, I know. I know some people are going like, and the only reason I don't have a stronger reaction to is I've seen so many times before. As we go through things, as we development from scratch and as sort of an idea starts in one place and by the time sort of enough iterations have gone through it, we end up somewhere else entirely and all of a sudden people love it. Rest, Bundler, at least for some people, yes, a pipeline for a smaller subset perhaps, CoffeeScript. There's sort of this transition phase which I find is strongest with people who sort of arrive that like, yes, okay, I have my setup now. I pack my personal backpack, my personal prepper backpack and it consists of these things and I got this duct tape and I put these things together myself and I really like it. And now you're coming out with a thing that kind of does some of the same things that I already had in my backpack, I don't like it. I have my thing, that's working well. Yeah, that's not great. It's a toy, not suitable for writing real, modern, ambitious, sophisticated web applications. That's a quote I just made up because that's sort of, that's how I process sometimes the feedback of what I'm hearing about turbulence. And I think, yes, most things start out as sort of a toy, as an experiment, as something fun. How's that a bad thing? When the fuck did toys become like, this is terrible? Toys are terrible. You are not serious enough if you play with toys. I love toys. I've always loved toys. There's nothing bad with toys. I mean, if we don't have toys, we're just adults, shit. No, thank you. So, here's Johnny. Turbulence 3 is, as the number suggests, the third major duration, which I don't even know what that means. It's sort of talked about like five. What does five mean? Why is five special? I think in many ways, again, it's so much not about the software. Like the version numbers we apply to things, they don't mean anything. We're just christening this commit. Like this is the one. Why wasn't it the one before or the one after? Nope, this is the one. Um, but it's a social thing. It's how we talk about things and how we get excited about things. Like you guys are just clapping rails five. Yeah, I don't know what's in it, but it's going to be great. And that's exactly that kind of enthusiasm and the power that version numbers have. And it's magical. Anyway, so, Turbulence 3, we're actually going to get to some code now. You thought there was not going to be any code, but there's going to be code. The thing about Turbulence 3 is it's getting greedy. Turbulence 1 and 2 started out with sort of a modest hope that, okay, well, we want the speed of sort of single page applications. We want the responsiveness of that. But let's just do it on the whole page. Like that was the first experiment, right? Like that was the first step and first approach of that. And that works very well for a subset of applications where you're not keeping anything permanent around from sort of page to page. Just about making the transition between the pages really fast. Well, not all applications are like that, right? So there were plenty of applications where somebody could look at Turbulence and think, like the idea maybe? Usually not. But I like the idea maybe, but it doesn't work for my app. Turbulence 3 is expanding sort of the circle of the apps that this will work for. By making it possible to have sort of these release valves, places where you can have some persistent data, some client-side state, and mixing it with stuff that doesn't need it. So this is a typical example, right? Like you're making an e-commerce app. There's a catalog. The catalog is static. Everyone sees the same catalog. Everyone sees the same product description, the same images, and so on and so forth. That stuff, you really want cached. You want it as fast as possible so it's that everyone is seeing the same thing. Anyway, perfect case for caching. Then you have this cart. The cart is per user. The cart is, at least in this example, stable across the pages. And usually the problem then is, well, fuck. Now I can't cached these pages, right? Because I have the catalog. I could have cached that. But the page also has the cart. Now I can't cache it. Boo-hoo. I'm going to make the whole thing as a single-page application. No. Here's what we're going to do. So in the catalog, the catalog sections, articles of products, and links to put it into your cart, all this generic stuff, we're tripling now. We're adding a new attribute called a data turbulence permanent. Permanent means that this part of the DOM will survive page changes. The same bit will get moved over as you move between pages if the same element is present. Now the really cool thing about this is that when you set down the initial page, there's not going to be anything there. It's going to be an empty block weighted to be lazy loaded, because that means that the initial page request can be fully cached, super duper fast, and then you subsequently request a lazy loaded cart that's going to fill in the side. And when you've done that first initial request, which only happens on the first visit to the store, it's now carried over. So you can keep that state, which means that you can keep displaying the products that somebody's put in the cart out in the sidebar, and that's great. And things can live on from page to page. That's a pretty big level up from what Turbulling's had before. It's much closer to what a lot of people within, perhaps prior, hopefully, have chosen to say, well, I have to make this as a whole single page app. And the way the flow goes is, so you put something in the cart, it's just a remote link, which leads to a controller that just creates an item in the cart, and then the controller or the view, you could have done it with the view. I like this flow. I like this flow because there's nothing specific to the view. I'm just calling a link to put in cart remote. There's nothing specific to the user. I don't need any JavaScript on that side. What I do do with the JavaScript is I set up this cart, right? So this has a little bit of the client side embassy, right? Like we're keeping the cart around from page to page, but it's just a dash or sprinkles. That's the word. And then you create an item for the cart and it goes into your cart, and then you respond with a piece of HTML. The same piece of HTML, the rendering of this item that goes into the cart that you can reuse in other places. This is where we're coming back to this idea of deintegrated system. That you never have to recreate any templates. You're re-using the same bits over and over again. You're only applying the sort of expensive, fancy client side MVC JavaScript techniques when they're absolutely necessary and when they're not, as in the case of presenting the catalog, you don't. You boil it down, you dump it down as much as possible to straight up HTML, and it's much faster. It's much easier to deal with. Another example. Streaming video sessions. For example, this. I don't even know on Confreak's side whether they have live comments. I've seen that on other sites. It's a typical example of an app that invites you to build it as a single-page app. Totally build this with Turbulinx3. So if you, again, imagine that there's a stream going and there's a live comment thread on the side that's being updated. You can add to it. Other people can add to it. It gets updated. HTML looks something like this. This is streaming video section. Then there's the aside, which is the comments. See, none of this is actually marked up with any specific Turbulinx decorating. Then when you add a comment, something interesting happens because usually the problem with the streaming video thing is if you submit a form and then it reloads, it goes to a new page, well, then the video is not really playing anymore, right? It reloads and it resets and like that doesn't work. Well, with this, you can use Turbulinx to say, I only want one part of the page to change. I'm re-rendering the whole damn thing, but I'm only changing in the DOM comments. You see, change comments, that matches the ID of the aside. That's ID comments. So it'll look at those two things and say, well, oh, I'm only going to change this one element of the DOM. I'll keep the video playing. This is going to feel fast, consistent, no hiccups in the video and so on and so forth. Awesome. This, by the way, is sort of why I think, perhaps, Turbulinx, this time around has a greater chance of striking resonance with people who have poo-pooed the idea in the past is that there's been another sort of trend in the JavaScript world that's popularized this idea that, you know what, maybe two-way bindings and maintaining all that crap was not the greatest idea in the world, right? React. Rerender the whole damn flow whenever something changes. Do not try to manage and update these individual little bits of state. If you subscribe to that idea, Turbulinx is much the same thing, just happening from a server-side perspective instead of a client-side perspective, which in my world means, in a great system, it means, I can use Ruby, it means all these other things. That I hold dear, yet we can share the same sort of philosophical underpinnings as the React approach does. So my hope that hopefully this will take us some of that way. Another common example of a page that, in the past, you'd have problems sort of representing well with Turbulinx and with a traditional approach to web application development is content with a personalized navigation. So you have something that says, hi, David, or you have an inbox calendar, you have other pieces and bits of information that are per user, and they're paired with this generic content that you want to cache for everyone. Well, again, much the same approach as what we did with the cart. You tag one part of the element data Turbulinx permanent. It stays from page to page. You can lazy-load it, and then all the rest of the content you can treat as though it was shared for everyone, and the app is much faster. Awesome. So we've been working on this stuff with the guys over at Shopify. They've been doing a bunch of work on Turbulinx lately. They used to have a client-side MBC framework called BatmanJS that after a couple years, they decided, it's so funny when I have to retell these stories, because I kind of get so giddy about how I want to phrase it, and they're like, oh, shit. If I phrase it too brazenly, then people are going to think, like, eh, you're just kind of rubbing it in, so you've got to be a little more diplomatic about it. That's that train that's going inside my head. So they decided it was not right for them to use client-side MBC for their particular situation with their group of people and their stakeholders and use cases. So they said, fuck it. We're going to throw it out, and we're going to try some Turbulinx instead. And that's why we've sort of, that's why Turbulinx 3 is here, because the great group of people at Shopify chose to invest in it. So they've been doing all this work with Turbulinx permanent, and they obviously have cases that are, oh, let's say, a little similar to that first example of a catalog and a shopping cart. Then we've been at Basecamp trying to hit it from another angle, which is part of this problem of the integrated system in a world where the iPhone and Android and all these other things exist is that that's a lot of work to recreate that all that stuff again, and we don't want to do that. So Turbulinx 3, we're working on basically creating native versions of that, which is, when I say native versions, I mean it's a web kit, and whatever the hell web kit is called on Android, wrappers that work with Turbulinx, such that links and so on are automatically intercepted. You can do these super-duper fast page changes. It feels amazing, and it's very hard to tell the difference between, oh, this was a native page, this was not a native page. We're going to bake it all in, and we're going to release it as open source, because it's awesome. So that's Turbulinx 3. I'm pretty excited about it. I hope that even if you didn't like the concept initially, maybe React has changed your mind on the wisdom of two-way bindings and so forth, and maybe it's time to give it another look. OK. So that's great. This is greater. Action cable. So at base camp, we're working on some new stuff at the moment, which means that I get to play with new tech in a way that I otherwise wouldn't have. Get to revisit some sort of core foundational assumptions and play with new stuff, which is a lot of fun. And one of the things I've been playing with a bunch is web sockets. So web sockets are pretty damn cool. And the only reason I don't think it's obviously it's used in a lot of applications already. I don't think it's used nearly widely enough, and it's because dealing with web sockets on the metal is a pain in the ass. And it's a pain in the ass currently for some of the same reasons that JavaScript used to be more of a pain in the ass, because there's different implementations. There's different ways, different browsers keep the connection alive, whether you can tell if somebody's locked off or not. And all these sort of different ways of working with the web socket is just kind of painful. So when I started working on web sockets for this new stuff I'm working on, I thought there's got to be a great application I can just rip off. It's much easier if somebody's just done all the work for that, and we can just look at something else and we can rip it off. No such luck, unfortunately. So actually, that's not entirely true. I did rip some stuff up from Phoenix in Elixir. It's done some really neat work on some of this stuff, and you'll see some of the reflections in it, but that kind of came later. Anyway. Broadening the horizon, making the integrated system capable of dealing with more types of things, using the same system, not how I want to have to build an additional element, you just want it all in your rail tap. This is Pinterest, and it has one of those examples I was using before for Turpolings, where it has a bunch of stuff that's common, perhaps. I can be cast, at least in this case, where you're watching a generic page or somebody's generic collection, and then it has this little thing up in the corner. It's really hard to tell on the screen, but it's an inbox, and it has a number. It says, like, you have three new things. Well, those three new things, obviously those are the ones that are sort of special to you and have to be updated, all this other stuff, the blue stuff, is all this stuff that's generic. Well, to update that counter, how are you gonna do that? Like, you could update it only when the person changes pages? Well, that kind of sucks. If they're just on the long page and something comes in, they don't see it. Well, you could do polling. If you're Pinterest and you do polling, that probably sucks, too. And it's at least not real time, it's not as fast. I actually happen to be sort of thinking that polling is a reasonable thing to do in a lot of circumstances, but if you can make web sockets even less work than polling, why wouldn't you do it? Why wouldn't you want it live if you could get it live? Another example, if you want the Nigerian Prince spam as soon as it hits your inbox and you wanna know about it right away whether you also have the opportunity of getting $21 million from somewhere in Nigeria, then web notifications is a really great way to get that. It doesn't require a native app, but how do you set these out? And often, of course, the whole purpose of web notifications is that they show up right away. They're a notification about something live. How do you deliver that? Web notification, or web sockets, again, is a great way of doing that. You're subscribing to something that sends them down and you get them right away. And then finally, of course, the prototypical example that's used in every single web sockets tutorial is the chat, right? That's even more interesting than the other two examples because the other two examples were mainly just subscribing examples. This is both receiving and sending stuff. Now, we made a campfire in 2005 and used polling at the time. It only polls once every three seconds and surprisingly, that's about the resolution that people don't even notice that. But that was 10 years ago and we basically haven't touched it since. So that's another good example of something like, okay, it worked well enough for 10 years. Let's see if there's something better. And even better, what if there was something where we could check all these three use cases even in the same app and use the same system to build it? Now, that would be really cool. That's what Action Cable is. So Action Cable is this concept of every user creating one connection to the application, one cable. That cable is a web sockets connection. You run one per tap or per browser or per native app or whatever. So one user can have multiple but one single section will have one connection. Over that cable, we layer different channels. Those different channels are the individual use cases. I just showed you three different channels. There's a channel for the inbox, there's a channel for the web notifications and there's a channel for the chat. No reason for us to create three separate web sockets connections to deal with that. We just need one and we can just interleave this stuff. It's kind of similar in some ways to what HTTP2 is gonna be like where you just have the one connection, you interleave stuff as it comes in much faster, much better ways to do things. And finally, you have the concept of the broadcaster. The mechanism on the server side that sends stuff through these channels to the user. And that connection in Action Cable is using Redis PupsUp because Redis is amazing and super duper fast and PupsUp is just stupid, simple and easy to use is great. So this is basically my very sophisticated enterprise-y diagram explaining how Action Cable work. Let's look at some code. So with Action Cable, as I said, you create one connection per session, per tab, per whatever you have. When you make that connection, you have to authenticate it. And that's one of those things that are not really necessarily that well-addressed in a lot of other WebSockets sort of setups. The way we're gonna address it is that to initiate a WebSockets connection, you're just initiating an HTTP connection and then it switches over. So you can do your authentication in exactly the same way you would do your authentication on a regular WebRequest. You can just use the cookie. So this of course requires that somebody's already locked in, but they already would be anyway to see the inbox, to see the chat, to see so on and so forth. So this connection, it looks kind of like a little bit like a controller, right? Like it looks a little bit like a before-action filter or something like that. What's different here is that with the before-action stuff, that only lasts the lifetime of that single request. Well, the whole point of our WebSockets is that they're consistent, they're persistent. So when you set this, this is a long-living threat. No longer just a throwaway thing. Now let's go back to the example of the inbox and walk through that all the way. So as you can see with this setup, you need a couple of different things. You need that initial cable connection. I just showed you that. That's just there to do authentication. It's just there to say who is the current user. Then you need a channel to say, I want to consume some stuff here. I want to consume what's going on in the inbox. That needs to happen in JavaScript. So the JavaScript says I want some of that. And then on the server, you need a broadcast or something to push stuff into the inbox. This is kind of what the JavaScript stuff looks like right now. This is all in CoffeeScript, by the way. And a work in progress and so on and so forth. But you create a new JavaScript side channel by descending from Action Cable channel. That channel has a specific name. In this case, we're relating that channel to a DOM element. That was that little icon up in the corner that says to right now, that's the DOM element. We like to do it with data behaviors. So call that data behavior inbox. So we have a way to refer to it. When we set up the document initially, we're going to instantiate this channel as a sort of a persistent thing. We're just going to put it in the namespace of app. You can put it whatever you want to do. This whole sort of structure and setup can work with pretty much whatever preferences you have on the JavaScript side. We like to do it just with plain old CoffeeScript. There's no additional framework here, except for the fact, of course, you're inheriting from Action Cable. Now, what's interesting here is the one method called received. So when you instantiate this inbox channel, it basically subscribes to the server side and says, I want everything that's coming in to this inbox for the current user, right? When something does come in, you get a callback, you get received, and that gives you the data. The data is just the JSON. It's just the hash of this stuff that comes down. And in the case of the inbox, all we want to send is when there's a new thing we want to increment the counter. Great. We have to have a corresponding channel on the server side. That actually, that's how you set it up. That's how the connection is made. What happens when this instance is instantiated, or this class is instantiated, it creates a connection to this inbox channel. It's routed automatically. We have a sort of little built-in router. That's where the channel name goes through. Automatica, automatically, matches up with the inbox channel. It calls connect as the first thing, just like when you're creating the cable connection it calls connect, when you create any additional connections to the channels, it calls connect on that too. And all it does in this case is subscribe to a specific Redis PubSub channel. And that Redis PubSub channel, we have to have a name for it. We just pick a name off the current user. You can see it here at the channel four. The channel four user is just inbox underscore, the ID of the user. You just need one per user. So you have something to send to. I've encapsulated here in an inbox class, which both is responsible for being the broadcaster, sending stuff down to the client side, but also responsible for keeping the state of this inbox, keeping the counter. In this example, I'm just keeping the counter as in Redis as well. I really find that these things they pair very well with Redis. Like a lot of these things with the WebSocket stuff, not only from the PubSub perspective of having a queue to send things out, but also from the perspective of having any sort of data store for transient data. Redis is just phenomenal and fantastic. It's so good in fact that usually my first instinct whenever I see a sort of raw piece of access metal is like, how can I build a framework on top of it? Redis is probably one of the first things where I've not felt that. Like the data structures themselves are just expressive enough that I haven't identified anything that could be extracted out. Anyway, as an aside. In this case, what happens is that there's something else in the system. For example, when you send a new message or whatever, it's gonna call inbox increment for that user. It can be a callback. It can be a specific thing in the controller. It can be whatever you wanna have it. It'll call increment when something new comes into that user's inbox. They'll increment the counter in Redis and it'll broadcast the count back out and that count is going to hit the received. It's gonna update the text and boom, you see it. This kind of seems, it's funny, when I went through the talk and I was like, this seems complicated, right? Like there's three moving pieces and all of a sudden, and then I remember back to, oh, compared to writing this directly to the metal, it's extremely not complicated. But it's sort of just sort of one of the natures of the beast. Let's extend it a little bit. Let's be able to send something back the other way too. So this inbox, at first, it could just receive stuff. That's nice. But perhaps you also just wanna be able to clear the count. Like I don't wanna deal with the inbox count right now. You could have a little X up in the corner or whatever. What we're gonna do here is on the JavaScript side, we're gonna have a method called clear. We can send that back. What it does here is just called action clear, which is basically a remote procedure call. It's gonna call back to the inbox channel and call clear on that. I've extended the inbox channel here to basically do the same thing. I've extended it a little further where you can see it would connect again these channels through a long lift, the threads. So you can actually set instance variables and refer to them later when you get these other callbacks. So we instantiate the inbox and then on clear, we just call clear on the inbox. And the inbox when it calls clear, it's just gonna clear the redis, and then it's gonna set the broadcast count of zero back down. What's neat about this setup is on the client side, we don't actually maintain the state there. It just sends clear. It doesn't actually do any of the cleanup because that cleanup will happen automatically when the broadcast is sent back out because zero is sent back out. So all recipients are gonna get this, which is another thing that's really neat about using this approach, especially with multiple clients. So if you have the same tap open across five different things, they all have the same connection. They all subscribe to the same channel. They all clear out at the same time. Okay, neat. Another quick example here of the web notifications. Again, that's just a receiving channel. Here's actually all the code. I ripped it straight out of what I'm currently doing to put it in there. That's all that's needed to make these notifications. Notifications are just gonna be sent down as a, again, as a JSON title, body, URL. I'm using Terpolings to go straight to it. So when you click one of these notifications, it'll use Terpolings to go straight to that page that it's notifying you about if the thing is open and I focus on the screen. Okay. Chat. The more media example. So in chat, I'm just taking one little aspect here because chat is actually a larger problem that does take a little more code than this, but let's just look at one example, which is receiving data from the chat room. So in this example, I can receive two different types of data. I can either receive a typing hint, which is the little bit of information that says JSON is currently writing and you present that perhaps above the inbox field or something else like that. So that's one type of data I can get down. The other type is of course a new chat line. And what I wanted to basically show here was how we integrate this again with the whole system. What we send back and forth over the channel does not need just to be JSON. What we can send back and forth over the channel can be entire HTML fragments. So in this case, when you receive a line, the client side is not responsible for constructing what that HTML looked like. You just get that from the server because it's reusing the same partial that it's going to use when it renders the transcript into the first place. It's gonna reuse it when it presents a snippet of that. You have this one partial you can use over and over and over again. And then it has a little bit of logic of how to deal with local lines. Like you wanna add perhaps a hint that you've added something locally and then you replace it when you get something back from the server. Okay, again, the channel here uses the same concept. You connect to it at first. That grabs the instance to the chat room. That's the way you interact with stuff and post stuff to it. And then subscribe to the room channel so that you get updates from that channel. In this case, different from the inbox case, this channel is shared. So there's one channel per chat room and everyone who's subscribed to it, they get the same thing. So you only need one pops up queue to deal with one channel, not one per person. Pretty neat. Here's that example of using the lines, sending those down as full HTML snippets, not as JSON. Again, the whole point with all of this, the whole point for tying it back to the integrated system is that you reuse and leverage the pieces you already have, the tools you've already packed as much as possible. You want that Swiss Army knife in your backpack to be able to do all sorts of things because you can only pack a few things. This backpack is not infinitely large if you wanna carry it as one person. And now I've really tortured this metaphor to death. But that's the concept of it. And I get that that's not the general way that people do things. The general way that we construct these things is generally like, well, that's unpure. Sending HTML just back and forth as whole snippets is not the way to do it. You should just send data back and forth because if you send data back and forth, you can reduce the server to just being an API and then in this fairy land, that same API matches perfectly for what you need for your native application with what you need for your single page app on the desktop, and it usually doesn't go like that. The underpinnings of this is we use sort of two ways of dealing with it. We have Event Machine that handles just the connection logic, creating and disconnecting these web sockets themselves. That's great, but it's not great for actually running application logic inside because Event Machine places all these restrictions on the kind of stuff you can run and it's gotta be non-blocking and so on and so forth. So we pair it up with threads. So when you see something like receive, that's running in a thread. It's not running in Event Machine. And it can do whatever it wants to do and it can use whatever existing models that you already have, which is, again, it's another example of using the integrated system you're using all the same models. Here you're just using them in channels. You're calling these same models in the controllers. You're calling these same models in the mailers. You're calling these same models wherever you're going to use them. So it basically, both of these two tools are examples of the self-reliance, using the integrated system to get undue amount of leverage. To be able to have tiny teams that can create these full service, full stack, full breadth, full spectrum of devices, applications without having dozens of people. And that really fires me up. I'm really excited about even 12 years into this that we can still expand that spectrum. That we can still make it more and more capable of just how much stuff we can do and that we can keep up. That we can keep having a fighting chance as just one person or a tiny team to make something that spans the full gamut of devices, which is sort of becoming table stakes at this point, and take up the fight to teams that might have 10x the number of developers, 10x the amount of money, all the VC in the world, so fucking what? Have a better idea, have a great tool set, be prepared, and we can take up the fight. Thank you very much. Thank you.