 Let's go ahead and get going. So hello RailsConf. It's been a pretty good conference, hope you've all have enjoyed it. So this morning we're going to kick off the alternative framework track. We're going to talk a little bit about how to build real-time apps with Ruby and Pac-Yau. I'm Brian Powell. I'm one of the creators of Pac-Yau. I play an active role in maintaining it today. 50% of my time goes towards building new features and fixing problems. I have the privilege of working alongside about a dozen or so other maintainers. We love this project. We love the little slice of the Ruby community that we've been able to carve off for ourselves over the last year or two. You can follow me on Twitter at BrianP if you'd like. So I'm curious, who here has heard of Pac-Yau before RailsConf? Okay, awesome, a few people. For everyone else, Pac-Yau is a web framework for Ruby. Pac-Yau is an end-to-end framework, so it doesn't work on top of Rails. You would use it instead of Rails in your stack. And Pac-Yau, we've designed it to be sort of a different take on building application for the web. And it's really different than what you might see in something like Rails or even other ecosystems. It's really nothing quite like it. So this being RailsConf, excuse me, I did want to take just a minute to say thank you publicly to DHH. A couple years ago, he was kind enough to offer his, you could call it an endorsement maybe, of some of the concepts behind Pac-Yau. This is why we do what we do, thank you DHH. So Pac-Yau, it lets you build server-driven applications that automatically stay in sync with the server. So what this means is Pac-Yau is a server-side framework just like Rails. On the initial request, Pac-Yau will perform the rendering on the server side, build up a full HTML response, send that down to the browser. That's presented in the browser just like any other HTML page would. Now, where Pac-Yau starts to differ from other server-side frameworks is this view in the browser automatically keeps itself in sync with the server. So what that means is if we're looking at a list of comments in our application and one of you out there adds a new comment to the list, we're going to see it immediately. Anyone that's looking at that list is going to see that change immediately in our browser, and the framework handles this for us. So as the developer, we're not having to move any of our application to the client. It retains this traditional server-driven architecture. So let's look at an example of that together. So this is a blog that we're building. There's kind of a story behind this. So we want to build a blog but we want it to be a little bit more than just a place to throw random thoughts out. We want to think of this more as a place to start a conversation, right? So we want to make this engaging for the reader, and we're going to do that in a couple of ways. You'll see the two counters. There's a blue one and there's a gray one. The blue counter indicates the number of active readers. How many people are currently right now reading this page? And the gray one is the total number of readers across the history of this blog post. Underneath that is a comment form, and underneath that is where the comments will be listed. Right now there aren't any in our database, so we see an empty message. Now this is built. This is already built in Pac-Yau. So let's simulate usage of this between two clients, and kind of see where things stand. So you'll notice as I'm refreshing, it shows up in the one client but not the other one. Same thing with comments. In fact, it's not until that second client refreshes their screen that they're going to see that new state. So let's fix this. Let's make this a little bit more of an engaging UI. So we're going to start by opening up our routes. This is going to look very different than something you might see in Rails. And we're not going to try to understand everything that's going on here. But what we're going to do, we're going to focus on our statistics first, the two counters. We're going to make those start to render in real time. Then we're going to test that out, and then we're going to come back and do our comments. So there's two steps that we're going to take here. We're going to find the bit of code that's responsible for rendering our counters, and we're going to add a call to subscribe. Great, I can see it right here. So what this is doing is telling Pac-Yau that we want to subscribe this rendered view to any future changes in state that might occur that would affect its rendering. So that's the first step. The second step is we're going to write a client-side JavaScript component. This component's going to be responsible for rendering the state on the client. Just kidding, we're not going to have to do that. We will not be writing any JavaScript today, I promise you. I didn't lie in my abstract. So in fact, adding the call to subscribe and telling Pac-Yau that we want this view to keep up with its state is all that we have to do. So let's go back to our browser and test this out. So we're going to reload the pages. Notice they're out of sync. We're going to reload one client. And all of a sudden the counters start counting together. We can continue doing this, okay? You can even see the blue and it goes down to one, and then it comes back up to two as the connection is lost and then reestablished with that second client. So we didn't have to write any JavaScript. All we did is told Pac-Yau what we wanted it to do and the framework figured out how to make it happen. So our comments still aren't really working well, so let's fix that next. So we're going to go back to our routes. Here's the code responsible for rendering comments. Add a call to subscribe, just like we did with statistics. And we come back to the browser, reload the changes. And if everything works properly, we're going to start to see comments show up. And in fact, we do. So one client adds a comment. Any other connected client's going to see it immediately on their screen. We could go the other way, too, if we want. And again, we didn't write any JavaScript to do this. This is all happening in a server-driven environment. You might have heard of Node.js, we embrace Node.js. And I kind of like to think that maybe this is what they were going for when they built Node. It was just a misunderstanding that somebody had a cold and they said Node.js and someone interpreted it as Node.js and went off and built that. I don't know, just a theory. And I want to be clear, I like JavaScript. I like writing JavaScript. What I don't like as a developer is having to write code that's largely unnecessary. And I think a lot of the JavaScript that we write today is completely unnecessary for us to do. So if we're not writing client-side JavaScript, how in the world is this working? And that's a fair question. Thinking through this, you might think, well, we're trans-compiling our view rendering code that's written in Ruby and we're transpiling that into JavaScript. And we're sending that down to the client executing it. No, we're not doing that. I don't think that's a very good idea. At the end of the day, this approach requires you to build an application in a particular way. It doesn't give you full freedom to build a traditional server-side application. So then you might think that, well, when the state changes, we're doing a re-render on the server. We're building up the new HTML and we're sending that down to the clients. And we're just doing a replacement of the DOM, or even part of the DOM. No, we're not doing that either. I think this is probably a better solution than the first, because at least the server is always doing what the server knows to do, and that is in a server-driven world, render HTML and send that down. So at least it has that going for it. What I dislike and why we avoided this in Pac-Yau's implementation is inevitably you replace more of a DOM than you need to. So we were really interested in performing the fewest number of DOM transformations necessary to render the new state. So how does this even work? It seems like we've kind of exhausted all of our potential options here. Well, we haven't. Pac-Yau works in a different way. And I wanna explain this, but to really offer a good explanation, we need to step back a little bit. We need to build up some context. Some context about how Pac-Yau started, the initial problems it was built to solve, et cetera. So, welcome to 2011. This is when we first started working on getting a real release of Pac-Yau out the door. It's been around for a long time. So I think the first release was August of 2011. And at the time I was working for Metabond, which is a consulting agency that I started back in 2007. We build web-based apps for all sorts of customers. We were working in Rails mostly at the time in 2011. We're still around today. We still do some Rails development. And for the four years or so that we'd been in business, we had some unique processes. At least I think they were pretty unique. At least at the time. And we called this process View First Development. Now, our priority with View First Development was to get something in front of project stakeholders that they could see and touch and use in a browser as early in the project as we could. So when we started a project, we would meet with project stakeholders and we'd determine what in the world it is that we're building. We'd figure out the feature set. We'd prioritize that. And we'd start with the top, right? The highest priority feature. The kinds of applications that we build are mostly, they mostly involve user interfaces. And so that was what we wanted to start with, because that is the tangible thing that we can play with together with the project stakeholders and really use that as a way to talk about some of the more abstract conceptual details of the feature. And the way we wanted it to work is we wanted to create a usable prototype building just the view. We didn't want to have to build a prototype application. We just wanted to write the HTML views, the thing that was presented in the browser and start there. So we'd use that, we'd deliver that in a day or two. We'd iterate on that with the project stakeholder. We could throw it out and start over if we wanted to because we hadn't invested much time. So once the prototype was nailed down, we wanted to build the backend on top. So this implies sort of this consistent forward movement. We didn't want to throw out previous work and start over. We wanted to build on top of everything that had happened previously. And the third goal of View First Development and how we wanted to be building our applications is we wanted to be able to revert back to the prototype at any point. So we don't build things in a waterfall fashion. We weren't prototyping the entire application up front and then integrating it into the application and then shipping it. We were doing this one feature at a time. And what we found with technologies such as Rails, and Rails is the only one that does this, most server-side frameworks do, is we'd build our prototype in HTML, ERB templates that just contained HTML. They didn't have the Ruby sprinkles. When it came time to integrate the feature into our application, we would sprinkle in the Ruby code and that pretty much destroyed our prototype. We couldn't just see the raw HTML without our Ruby sprinkles. So we kinda destroyed it. So that meant when we started building the second feature we could see its prototype but we couldn't see it in context of the original feature's prototype. And that made it kinda difficult working through that with stakeholders because they didn't understand why they couldn't see the same thing that they saw before. So we really wanted to solve that. And that ended up being really difficult. So we did the only logical thing that we could think of to do at the time and we built our own framework to solve this very specific problem. When we set out to build Pac-Yau, we really had this one goal. This is a pattern that I and a few others had noticed in every single web technology that we'd ever used since we started building it, I guess early 2000s is when I started. And that is the presentation side of web applications combined two things that we thought were really separate and should be treated separately and those are view structure and rendering logic. So if we look at an ERB template, here we're just iterating over a set of posts and we're rendering an article for each post and we're putting the value of body into the BearGraph tag. And there's two things represented here. There's the structure of the view, which is the HTML and there's the logic to render it and that's the Ruby sprinkles. And this, if you look at this, it has some semantic meaning to it, the ERB template does, right? We can look at this and we can see that our article tag really does represent a blog post or a post object in this case, right? Because we're creating one for every post that we have and our data set. And we can also see that the paragraph tag represents the body because that's the value that we're sticking into the body tag. So this ERB template has some amount of semantic meaning to us and that's lost when you build it because you end up with just the HTML. So you lose the semantics of it. So we set out to try to save this. So what you see at the bottom is a Pac-Yal view. It's the same exact thing as the top. You'll notice there's no Ruby code in this but there are however two attributes. There's a data scope and a data prop. Now in Pac-Yal terminology, a data scope represents a data type. So here we're saying that this article represents a post in our system and the paragraph tag which is nested within the post represents an attribute of it. So the paragraph tag represents the body of its parent scope or post. And that's all the view is in Pac-Yal. We can stop there. Now the logic to render it looks something like this. This is just an example. This is, there's many different ways that you can do view rendering in Pac-Yal but this is a simple one. And you'll notice that this doesn't really look like we're rendering HTML. There's no DOM transformations that we're needing to express. Instead what we're doing is expressing our rendering logic in context of the semantics represented by the view. So we're not saying find the article tag in the view and render that. We're saying find me the node whatever it happens to be that represents the post in my presentation and apply this data set to it. Now apply is not magical. It's actually pretty simple to understand. So let's look at a couple of examples. So if we have a hash, just a single post object that we wanna present and we apply that to our template, what apply is gonna do is two steps. First, it makes the view template match the data structure that we're applying to it. So here that's easy, there's no changes required because our template already represents a single post. We're only applying a single post. So all apply has to do is map the body value right into its place in the template. So we're left with a result on the bottom. Looking at a little bit more complex example with two posts, now apply has something to do, right? Our template only represents one post but we're trying to present two. So it creates a duplicate and then it can simply just map the values into the view and that's all view rendering is in Pac-Out. Okay, so let me wrap that part of it up, right? This allowed us to do exactly what we wanted. We could prototype writing the HTML. We could add the backend code. We didn't have to change our views to do so and at any point we could just turn the view rendering part off and we'd be left with our prototype. So we effectively solved our goals. So we built applications this way for a few months and we quite enjoyed it and I had this idea, this sort of nagging feeling in my brain that I couldn't shake. Now, keep in mind this was right around 2012-ish and single page apps were starting to become more popular, gain more momentum as were client-side frameworks and I couldn't shake the feeling that maybe we had something to offer to people who wanted something more than just static views presented in a browser but really wanted a dynamic user experience and I thought Pac-Out might have a unique solution to this and it stemmed from this one idea. So this is our first rendering example and you'll notice that our rendered view still has the semantics that the template has. We still know what every node represents in this rendered view. Okay, so we can actually use that previous render as a starting point for the next one. So if we add another post to our state, we don't have to start with the original template, we can start with the first render and just build on top of that and we're left with the exact same result. So it was this idea that rendering is additive and the code to render the initial view maybe it's enough to also render changes to an existing view. Now, view rendering in Pac-Out happens on the server. It's presented in the browser and that means what's presented in the browser still has those semantics. We know exactly what it is that it represents in our application. So we already have that piece. We already have a template that we can work from. So all we need now is to get the transformations down to the client and theoretically with some magic we can make the client update itself. Okay, so let's walk through a full example of this. So we have the client in the server. Client asks the server for the initial view and the server responds with a full HTML response presented in the browser. Now, subsequent updates. They also originate from the server. So the server is telling the client how it can update itself. And this happens with something called UI transformations and the way that we build these transformations is we execute the exact same rendering code that we used for the initial render but instead of rendering HTML we just record the transformations that need to occur. So we're not transpiling that code into JavaScript. We're just creating a set of instructions for the rendering that should occur to reflect the new state. Now, that's just data at this point. It's just a large data structure. We can actually serialize that. So that's what we do. We serialize it as a JSON object and we shove it down a web socket to any client that should be concerned with the state change. Now, there is a client-side library that's part of Pacquiao called ring.js and ring is what receives these transformations and does something with them. So ring, it has the template, now it has the transformations and all it has to do is step through the transformations and make the necessary updates to reflect them in the view. Now, this happens through something called the View Transformation API. So because we've separated our view structure and our rendering logic, we're left with this nice seven methods or so of how we express our view rendering in our Ruby code and we implement that on the back end in a class called presenter. Presenters the thing responsible for doing the initial HTML rendering but ring.js also has a client-side implementation of the same API. So when it receives the UI transformations, those transformations are expressed in this common API and ring can just iterate over it, call the right functions on the client side and it's gonna make the browser reflect the new state. So Pacquiao falls somewhere between a traditional and a client-side framework, right? It's server-driven, it's a server-side framework just like Rails, we're getting full HTML responses but once rendered, we're really getting this client-side behavior but again, we don't have to move anything over to the client. Not even Pacquiao has to move anything to the client. All of our code stays Ruby code and it stays server-side. So thinking about how we might do this in other server-driven frameworks, inevitably we adopt some sort of hybrid approach. So let's just use Rails as an example. If we care about building our real-time blog in Rails, we might do the initial rendering on the server, right? So that we can still send the full HTML response back. Then we might use some client-side tool, maybe Ember.js or Backbone or maybe you could even use ActionCable for some of this and that component is responsible for making the client-side state changes as it needs to. So we get that dynamic view but what we've done is we have two problems now, right? We have two code bases that are executed in two different contexts and they're both concerned with the same thing and that is how to render our state. Some of that's on the server, some of that's in the client and this just kind of creates this web of complexity and it leads to more complexities the further down the rabbit hole you go. I think this is largely why people started building single-page apps to begin with. It's conceptually simpler to understand, right? We started off and we were building a server-side application. We only dealt with state on the server. Now we've got this hybrid thing and we have to manage two code bases that both render state. So let's just move it all to the client and do it there. And on the surface that kind of seems maybe a good idea and maybe for some kinds of applications it is a good idea. But I really think that single-page apps break the web and this is a pretty bold statement but I really believe this. If you look back at the entire history of the web, it started off as the server-driven thing. It was a series of hyperlinked documents that were provided by some server and you were guaranteed to receive exactly what you wanted back in the response from your request. With the single-page app model though, if I request a blog post, what I'm gonna get back is an empty skeleton of an HTML file with the JavaScript include, hopefully I can load the JavaScript, the CDN's not down or something. And if the JavaScript can be fetched and can be executed, then it's gonna make another round trip to the server to get the data through our API and then finally we can do the rendering, right? And this is a complete departure from how we've been building applications for decades. This isn't how the web works. Every successful technology built on the web builds on everything else that was there before and it just feels like a shame to throw out the server-side applications that we've been building for so long. So in Pac-Yal, we implement real-time as an enhancement. So thinking back to our example application, what we first demoed and what we first saw in the browser was just a static view, that's all it was. Just like any other backend-driven application like a Rails app or a PHP app, it was the static thing that didn't change in front of you, right? And what we did is we went into the backend code and we just told the framework that we wanted it to be subscribed to state changes. That's all we did. And the framework added that into our application but it did so as an enhancement. It's just a layer on top. The application continues to work even if real-time doesn't work. So let's say, for example, someone visits our application without JavaScript. Well, no problem, the first response is a full HTML page. It's already rendered, we can present it. Well, that's not very likely, right? No one disables JavaScript anymore. Well, what if your CDN's down and we can't fetch your JavaScript? That happens to us. Maybe we're just not good at ops but I think that's a common problem. Not a problem, right? Same thing, we still have a rendered view that we can present in the browser. And I think this really reflects the spirit of the web, right? It really is real-time is an enhancement on top of how we've been building applications for decades. Lastly here, I love Ruby and I don't mind JavaScript but given the two, you know which one I'm gonna pick. I love the language. And that's what drew me to Rails, right? In 2005-ish when I first started hearing about this thing I was like, oh my goodness, look at how we can build applications. This is awesome. I've been stuck in PHP for so long and I've lost my soul and here's this awesome way of building things. And Rails has a lot to do with that. Rails is a fantastic tool. It allows us to build things in a much simpler way than before with good patterns and processes. But at the heart of Rails is Ruby and that's what I really wanna build my applications in. I think as developers we need options. We need options for how we build things. I don't like this migration towards the client and even on the server having to write JavaScript to build our applications. That just seems like a shame. So where's this project going? So this real-time stuff has been out for about six months. It took about two years of work to figure out how we were gonna make this work. But it works. There are production applications. Some of them we've built, some of them we have not that use Pacquiao UI and Pacquiao real-time to provide these dynamic views to people in the browser. So we feel like we've solved the hard problems now. Like we've got all that figured out. Now we just have to make it a better framework because if you've ever tried to use Pacquiao documentation's not great, the APIs aren't exactly perfect and those are the things that we wanna fix. We really have this vision for Pacquiao makes it possible for people to build applications in a completely different way and to build these server-side applications that feel like modern client-side apps. And we wanna bring that to people but more than that we want this to be the easiest way, even easier than a client-side framework. We want someone to be able to pick this up, build these applications, do more, much easier. And that's really the focus of 1.0. So hopefully it'll be out later this year. We'll see, we're not really putting a date on it. We'd love your help. As I said, there's a small community around this. We're really passionate about this project. I think you kind of have to be to work on it for five years. I love building apps in this way. You can read more about Pacquiao. We have a website, pacquiao.org. We've got guides and documentation. You can build a real-time chat app in, I won't say five minutes, but half an hour, say, fair enough. And we walk you through how to do that and deploy it to Heroku. We're on GitHub. Give us a star. Follow along the development. There are open issues at pacquiao slash pacquiao. And on that note I did wanna mention that we've started doing this thing with our issues. We label some of them as starter issues. So we're really interested in pulling people from the community in. And some of these, because pacquiao has such a weird approach to things, people didn't really know where to start. They didn't have the confidence to begin. So we went in and said, okay, yes, this. It's like two hours or less of context building, we promise, and you'll be able to complete this work. So if you wanna find a place to jump in, look for a starter issue, you can follow pacquiao at pacquiao. You can follow me. I'd love to talk more about this. This is something that I'd love to talk about. Thank you very much.