 All right, let's get started. So today we're talking about the Phoenix framework and kind of my goals for it, the features that we have so far and where I want to see it go long term. So I'm Chris McCord. For those of you that don't know me, I work at a consultancy named Little Lines. And we're primarily a Ruby shop. We do a lot of Rails apps. And so the nice thing about working at a consultancy is I've gotten to work with a lot of different services. We build web apps and web services. So I have gotten experience with a lot of different problem domains and solving a lot of different problems. So Phoenix has kind of derived from that experience. I want to long term use it to replace all of my client work and everything I want to build personally with Elixir. So my goals are nothing short of a web framework that can accomplish that. So what are we talking about today? We're talking about why am I doing this? Why do I think that Elixir needs a web framework? And what do I mean by web framework? And kind of the main features we're going to review. We have a really nice, robust routing layer. We have a nice, routing DSL. Something I'm super happy about is our WebSocket and PubSub layer, both on the client and server. So currently we ship with a small browser JavaScript dependency to wire up with our real time back end. It's about 130 lines of JavaScript. And it's super nice. And my co-worker is working on a Swift client, natively in iOS, so I'm super excited about that. And we have plug-based routers and controllers. So Jose has put together this really awesome plug middleware library, so we integrate with that. So if you're not using Phoenix, or if someone puts out plug middleware, it should just be able to plug right into Phoenix so we can have community support for folks that aren't in Phoenix directly. And we just shipped a pre-compiled view layer recently, still in flex a little bit, but I'm super happy with it. It's highly performant. Everything just compiles down to function definitions. So at runtime, you're just basically doing string concatenation, so it's super nice. And we'll talk about the future and my ambitious goals for the framework and where I'd like to see things go long term. So why Elixir Web Framework? I don't want to rehash why Elixir, because I think everyone has talked about that today. But I haven't heard this quote, which could get me into trouble. Elixir lets me do what if I could just driven development. And you have to be very careful with this. So this is kind of a joke, but it's actually completely true. You have to be very careful designing with this mindset. This is really just API driven development, or read me driven development with metaprogramming on top. Not everything you think of solving in this mindset actually is the correct way to do it, but for certain aspects, especially at the framework level, our goal is to make our users' lives easier. I've thought about developing features this way, and I'll show you later how this kind of thinking has brought about some neat features. And for me, this is the game changer. Being able to say, how can I accomplish this goal in the easiest way possible in whatever domain I'm operating in? And Elixir lets me do that pretty fantastically. And then the obvious cases of we have the trifecta fault tolerance concurrency and distribution with metaprogramming on top. And not many languages even have the three at the bottom, and then you put metaprogramming on top, and it's amazing. So I think Elixir is the only language that I can build out the kind of applications I want to build today that I've had experience with, at least. So what do I mean by web framework? And I don't know if Dave's in here, but I'm not just trying to replicate Rails. So I'll just shut that down right now. But I do Rails full time. I really enjoy the Ruby ecosystem. So some ideas have been borrowed, and I think Rails got a lot more right than it got wrong. But I'm not trying to recreate a web framework that just generates HTML, trying to go beyond what a web framework even is traditionally. So I think what we're really building is a distributed web services framework. And I have hesitated to call it that because I think it might confuse folks. And I'll get into what I mean by that as we go out through the slides today. But I think web framework today, the web is more than HTML in browsers. I think the web is here to stay. I don't think the web is dying, but I think the web is evolving into what we think of as the web. I think what we really need for a modern framework is a connected devices framework. We have the internet of things. We have iPhones, Android phones. We have smart ovens, smart toasters. And I think we have to have a framework that can connect all these things in a single back end to be able to provide some kind of service. So that's Phoenix's goal. I think if you want to just use it to render HTML and separate it to a browser, it will do that super well. But my goals are to go well beyond a framework that's just good at building HTML web apps. And our goals are batteries included. So I'm not afraid to add features where they make sense. I think the term micro framework doesn't make a lot of sense. I think libraries are great. Use libraries if you love libraries and like throwing your own code. But I think a full-future framework that has shared conventions allows a community to get together and build awesome things. So we're focusing on convention over configuration, but with reasonable conventions. I think most people agree with what we've put together so far. I don't think we go too far with it. But great things happen if we share the same language and the same conventions. Third-party libraries can be easily integrated. And I think Rails above all things has proved that. So my goal is to have a vibrant ecosystem around Phoenix and plug and be able to build out great tooling as a community. And obviously, we focus on ease of use, just like Elixir does. Common tasks should be easy. And especially for me coming from a Ruby background, things that are historically hard for me to do in Ruby I've made easy and simple in Phoenix. So this is like web sockets, publishing real-time events, service order and architecture. These things are actually historically hard, at least coming from a Ruby environment. Most of our languages, we think of like, OK, let's sell out service order architecture is great. Microservices is a hip thing to say lately. But there's a lot of fanfare with other languages. We have to, in the Ruby world, we just split our apps up, put some REST APIs in between, and that works. Or we throw Redis in between our apps, use Redis as a bus to talk between the apps. And that's not a bad thing to do. So don't misquote me and say, you know, Chris McCord says, JSON APIs are terrible. I think this is actually a smart way to distribute out services. But with the Erlang VM and distribution, we get so almost for free, right? We send a message. It's location transparent. It could be anywhere on the cluster. So we can run an entire umbrella project, so to speak, and we're serviced out automatically under the single code base. So I'd like to explore that with Phoenix and really focus on service-oriented architecture without all the caveats of having to split our app up into RESTful APIs right out of the gate. And then a little play on words here. I have a goal of no productivity sacrifices for performance, and no performance sacrifices for productivity. I think Elixir gives us both. I come from a Rails background where I'm incredibly productive. I love the code that I produce. But there's always this caveat of, like, ah, it's kind of slow. I think with Elixir we can get the productivity without having to make our code super dense to get performance. And we can also, with Phoenix, we want to make our users super productive, but we also are focusing on making things highly performant and keeping up the performance, not at the cost of productivity. And I think Elixir gives us both. And I've run some benchmarks, and I'm pretty happy with the performance so far. So enough talking. Let's see some code that's hopefully large enough to read. This is our routing layer. We have a really nice routing DSL. Git post put deletes. Is it going to map out some endpoints for you? And you map that to a controller. So if you had a pages controller here, that's just going to be a module. And then we refer to the function that your controller is going to have invoked for that match in that controller action. So we map to a request path to a controller, and controllers carry out some action. And then we can use this nice resources macro. And if you're coming from Rails, that we borrowed this. This is going to map out some conventional restful endpoints. So instead of you having to map out a bunch of restful endpoints for a user's resource, like the list of users, creating a user, updating a user, it's going to map those out automatically. And then we can even nest macros within that. And what this allows us to do is expand that at compile time to automatically build up the nested restful path with all the nice parameters in the URL for you automatically. And you might be thinking this is really pretty, but is the code crazy? A lot of people like to rail on macros saying they hide complexity, but we're striving in the framework to produce macros that make sense. And what happens at compile time is that module we just saw, I had to split it into two code blocks, compiles did just a bunch of function definitions, all named match. And Jose first did this in the Dynamo framework. So this is an awesome idea, so I can't claim the thought here, but I borrowed this in Phoenix. And it's super nice because after this is compiled, we have a bunch of match definitions. And we're just relying on pattern matching to actually do 100% of the route dispatch at runtime. So this is incredibly performant because the virtual machine just takes over. We get a request from the web server. We split the path by a forward slash, and then we literally just call router.match pass the HTTP action in the list of split path segments. And then 100% of the route dispatch is handled by the early virtual machine. And what we do within those match bodies is a single line of code generation. So let's say we have a macro get to some path, and then we'll say we want to have some parameter on the end named slug, maybe like slash pages slash about. We want to map that to the pages controller show action. Internally, that just looks like this. We generate a single line of code for that function body, and then we delegate out to another module as soon as possible. So when we're writing macros, we should always be striving to generate as little code as possible. And Phoenix, I think, has done a good job of that. So if you ever want to level up on your macro knowledge, take a look at the code base because I'm super happy with what we've done with it. And we can see how the pattern matching kind of takes over. If we get a request to get to slash pages slash about, we just split that by forward slash, and we just call router dot match, and we can see that the slug was matched as a variable binding, not a string. So then slug contains the string about, and then we call a controller perform action, pass in that name parameter, and then the controller later takes over. And the same thing, it works quite well for a splat named parameter. So if we have get to files, asterisk path, what's going to happen there is the asterisk path means anything after files, it could have forward slash is in it. We want that to be the entirety of the path argument. So what we do is we generate a function that's very similar, but we use head-tail pattern matching here. So if we have get to slash files, users slash first slash downloads, we generate a function definition named match. But if you notice, we generate the AST for a head-tail pattern match there, and that allows us to have splat arguments, and it's just a head-tail pattern match on a list, which is super nice. So still we were able to support splat arguments with a 100% pattern match at runtime. And then we have a controller layer, and this is still in flux a little bit. I should mention that if you're checking out Phoenix, check out the master branch, because I was hoping to have a new feature pushed out with a dozen awesome additions, but I didn't have time before the conference. But in master, controllers are also plugs, just like the router is. And Jose and I, and the core contributors, are in talks about being able to write a macro layer on top of plug. But right now, you can just plug controllers, as like Devin showed the plug library earlier. My goals with this are we can still get an explicit operation on our request connection, but a really nice high-level layer on top. So if you see in the controller, I can say, just start plugging functions to call. So at the top, I want to say when my request comes in, I want to plug authenticate, so the very first thing is I want to authenticate the connection. All that does is implement the plug contract that says you take a two-airty function, and you return the connection. What you do within that connection or update the state is up to you. So let's say in our authenticate, we want to assign some current user. Otherwise, we're going to raise an error, and it's going to halt the plug stack. And then if that passes, we plug action. And action is the function that matches in the controller. And that's going to call our show action in the pages example. And you can see that you get your query string parameters passed in as a map, which is kind of nice. So we can pattern match directly on the query string parameters per action. So if you had specific pages, if you had pages about and you wanted to run a different function, you just defined multiple function heads, and you get to use pattern matching, which is super handy. And then we can also call render. So the view layer landed very recently. Let's you just call render show. So I want to render a show template. And the nice thing about this is it's going to use the request accept headers to determine what template to render. So you might have a JSON template or an HTML template. You send a JSON request. It's going to send you JSON. You send a HTML request. It's going to render HTML. And then I have it commented out, but the nice thing with plug is it's just a list of functions, a list of transformations to perform on a connection. Since render in the Phoenix controller takes a optional third argument, it implements the plug protocol by default. You can send render a connection with a second argument. So we could literally plug render, and it would automatically render the action for us. So we get the implicit rendering from the rail side, if that's what you like, but it's still explicitly plugged in our controller. So my goals with this, especially with functional programming, is to make the implicit explicit. But I'd like to do it not at the cost of productivity and nice APIs. So I think plug gives us that nice middle ground. And Jose and I are in talks about building out a macro layer on top of plug to make this a little bit nicer. So if you check this out later, things could change a little bit. But ultimately, controllers and routers are plug-based. So anything that you can do in plug, you can do in Phoenix. And we have views and templates that landed recently. This trips some people up. When I was first looking into this, Jose told me that don't call views and templates different things. And I think that was fantastic advice. Most frameworks or web frameworks I've seen either call views, templates, or templates views, and they're all the same thing. But in Phoenix, views and templates serve different purposes. So put simply views render templates. So templates are going to be your template source code. And views are going to actually carry out the job of rendering those templates and serve as a presentation layer for the templates. So every function you've defined in a view serves as a presentation layer. So your templates are rendered in the context of your view modules. And we've built out a nice module hierarchy for shared context. So you could have a base view where you want to say, OK, I want internationalization. I want currency formatters. And you want to import those into your base view. Those are automatically going to be in the context of all sub-views. And I'll show you how that works. And templates are all pre-compiled into views. So there's no evaluation at runtime. It's super performant. And we get a really nice layer of EEX and Hamel. For those of you that like Hamel, Johnny was working on Calliope and he got that in just before the conference, which is super nice. So they both work. Calliope is optional dependency, but it's there. You just drop it in your project, and it's super nice. And also pre-compiled. So here is a base view. This is generated for you when you run the Mix Phoenix new command. We have a Bootstrap project command that will generate a Mix project for you. But you could write this yourself. Hopefully I had to bump the font size out a little bit. But the nice thing about this is this serves as your base application view. And notice how we're not hiding the fact that Elixir allows us to define using blocks to inject code. We just say that you define a using macro, and then you can do any kind of code injection you want to do imports, aliases, whatever you would have you for the entire rest of the view layer. So if we want to alias any module, so within all our templates, if we often call out to a certain module, we can just pop that in our base view using macro, and that's injected for us automatically. And then since we also import all functions for you from the app.views, it's going to be my app.views module. For example, if I define some new line to be our helper, it's going to split a string by new line, add line breaks, but make an HTML save, I can do that here. And then that's just available automatically in all my base views. And we can see that by defining, when I said render show in that page controller, I would define by convention in app.pageView. Actually, it should be singular page view, not pages view. We had some naming convention changes recently. So if I had a page view, I just used app.views, and then everything within the using macro was just injected for me, and that's how I get that shared module hierarchy. And then I would define my own template context helper functions here to serve as the presentation layer for my templates. So let's say a page view has a title function that we want available to our templates, takes some page struct, gives us a pretty title back. That would be available in context of all of our page templates in addition to the base layer. And here's a template, EX, should be pretty familiar. We can just go through and call that new line to BR. It's just automatically available in the context of the template because of that shared hierarchy. So it's really nice. And it's all pre-compiled, so it's super fast. So here's a little bit of directory conventions. We have a views directory. And within that, you add a page controller. Phoenix expects a page view module. And then outside of the views folder, it expects a templates directory. So if I'm rendering the page view module, anything within the page directory in the templates folder, all those template sources are going to be pre-compiled into the module at compile time. So you just throw all of your templates in your page directory at compile time. It compiles them and pre-compiles them as function definitions on your view module. So at runtime, it's just a function dispatch. I show that here. You can just go open up IEX directly, invoke page view dot render, give it a string without the template source extension, and it renders that and returns you a string. And the nice thing about this is, and this is something I mess from other frameworks, is let's say I want to render JSON. I could throw a .json.ex like a show.json.ex in my templates folder, but JSON really doesn't need to be rendered through EX in most cases. You should just construct it as an Elixir map and return it to the client. Since our view modules are just creating function definitions pre-compiled at compile time, we can just define a render function within our page view. Our page view has a bunch of render functions defined automatically for every template, but we can just use pattern matching and say, you know what, if I render index JSON, I just want a pattern match on that template name, and I'll do my own JSON encoding. Because the contract is, you just have a render function. It takes an action name with the mime type extension, and then it has to return a string of whatever the template is. So I see a really nice layer of Phoenix apps that have view modules that are just responsible for rendering things. Some of those things may be templates, and some of those things would just be JSON or whatever you want to render directly as function definitions. So it feels like this really powerful magical layer, but ultimately it's just function definitions, all name render using pattern matching. So you kind of get the best of both worlds. And now we can go over channels, which is my favorite feature. I actually think this could attract a lot of people to the language itself. And this is why I ship channels before we shift the view layer, because notoriously doing any kind of web sockets or real-time events in Ruby has been very difficult. So I'm excited to see what people build with this. Channels are a web socket in PubSub abstraction, and they're a way to handle socket events and broadcast events. And we also built in a skeleton for authorization. So we don't do authorization for you, but we force you to perform authorization. Because if you're doing all this broadcasting and publish, subscribe, you want to be able to handle, is this person allowed to subscribe to this event? So we force you to define that. And we ship with a Phoenix.js browser client. I said it's about 130 lines of code, but it does multiplexing for you. It gives you a nice socket.io style API if you're familiar with that. And it just works. And we have a mobile iOS client as of this weekend. I've been pestering my co-worker, David Stump, for about the last two months to build me a iOS client. And he finally did. So I'm super excited about that. And if you're into Android, we'd love an Android client as soon as possible. Jose and I have been talking about making the channel layer less. It's all web sockets right now, but maybe breaking that out to kind of any protocol and being able to serialization to a native job app or any kind of platform. So I'm super excited about this concept and where it could go. And just to prove that it's a multi-platform, I have my contrast. This looks a little bit odd, but there's a Phoenix chat app in the background that's an HTML and JavaScript app using Phoenix channels. And then there's an iOS simulator in the foreground that's a native iOS Swift app running Phoenix channels with the same channel back end. And it's native. So that's not a web view on the iOS simulator. That's a native Swift library implementing the Phoenix channel protocol. So I'm super excited where this goes. And again, this is revolving around connected devices. We have a back end that can handle my iOS app, my Android app, a browser, my toaster. We have the internet of things happening. And it sounds silly, but I could foresee a future where I have a web front end that my power company has built. I can get statistics on my home devices and then my toasters reporting events on a Phoenix channel. And they're all talking to each other. That's not out of the realm of possibility. And I think we have to have frameworks that embrace the internet of things versus the browser of all things. So the channels have three parts. One is at the routing layer. And this is the what if I could just driven development in action here. So I have this nice HTTP routing layer where you could say get post put delete and it just worked. And I started with thinking, OK, I want to do a real time layer with web sockets. How could I go about this? So I opened up one of my routers and kind of a prototype app, and I said, you know what? What if I could just type channel here? And that would handle some kind of channel name and a module to handle those events. And that's it. That's the most as I had thought about it at this point. So I started here, and then I said, OK, how do I go about implementing this? So here's one case where that works really well. But again, I want to caution everyone with not everything should be thought of this way. But as a framework author, we get to get away with a little bit more metaprogramming than some people. So we're kind of spoiled in that regard. So the only other thing you have to do is just use Phoenix Router socket and give it an endpoint. So it's opt in. And then it wires up the WebSocket handler with the web server underneath for you. So the next part of it is a channel handler. And this is a module you define. And this is where we force you to handle authorization. So we always force you to define a join function that takes a socket, a topic, and some kind of message. So you can almost think of channels as controllers from like a REST interface with bi-directional data flow. So channels broker requests about a particular thing. So if we had a chat room, we might have a rooms controller that was like a REST interface. We're going to have some room channel that's going to handle things about a chat room. And then a topic is going to be a specific thing on that channel we want to talk about. So this is almost would map to a RESTful ID if we're talking about controllers. But we went for a more general sense of just we're talking on a channel about a particular thing and we call that topic. And the biggest point with the join function is you have to return OKSocket if this socket is authorized to join. Otherwise, you return AirSocket some kind of reason. So we force you to handle authorization, but it's up to you how you want to do that. So what would normally happen is let's say a socket wants to join the lobby topic, which is going to be a global chat room. This doesn't require authorization since it's a global chat room. So we can just reply to the socket directly. We have this really nice API that says, OK, I'm going to reply to the socket. Some kind of arbitrary message saying, hey, you've joined, your status is now connected. And then if I want to broadcast out to anyone listening on the lobby topic, I just say broadcast, give an event, user entered, and then I can give it a map that gets serialized as JSON today. And that gets broadcasted out to 10,000 folks listening. And then I'm done. And then I can define events. So your channels are going to probably define multiple events. And you just pattern match on the event name. So for a chat app, we have to be able to handle messages being posted. So I can say, OK, def events. And then I want to match on the new message event. So I match on that directly. And then I get the map as a third argument. So I can pattern match on the map directly in the third argument, which is kind of nice. So I'm super happy that maps landed, but let me do that. And then all I'll do for a chat app, we don't have any database back in for this chat example. So we just rebroadcast that out. So we get an event, new message from a single client. And then we just call broadcast. We want to rebroadcast that out to anyone listening on the lobby topic. And we just forward that message along. Then we return the socket in case we updated the state. And then the third piece of this is the client. So here's our JavaScript client. So the last two slides you saw on this slide is a complete Phoenix chat app, other than the HTML. I'm not lying when that's all that's required. And then we ship with this really nice JavaScript layer where I can say, you know what? I'm going to create a new Phoenix socket. And that's going to provide me some nice kind of functions. So if I want to join a channel, I say, I want to join the rooms channel. I give it a topic lobby. And then the third argument is going to be some JavaScript literal, and that's going to be any authorization data. And for our case, we're not doing authorization, so we just pass up an empty object. But in your more realistic sense, you would pass up some kind of auth token, something that you've previously sent down to the client that lets us know on the back end whether or not they're authenticated. And then for a chat app, we can just say, you know what? When some user presses Enter on their input, we just say, chan.send, give it a JavaScript literal that maps to our back end. And that was the event you saw back here. So when I say chan.send new message, I give it some arbitrary JSON object. And then that's what I pick up on my back end, new message event. So it's super nice. It maps back and forth really well. Likewise, when I say broadcast new message here, I broadcast that to any subscribers. So the client can subscribe to channel messages by saying chan.on. So chan.on is going to set up a subscription for, hey, when I receive a new message event from the channel, do something in this callback. So for our chat example, when we rebroadcast out the message, we just append it to some DOM element and we're done. So that's a full chat app. I think it's pretty awesome. And I think people could build games with this, internet of things. You could do all kinds of stuff. And I know if some people today are actually building out different kinds of games with it. So I'm super excited to see what happens. And another neat feature, which hopefully really drives home what you can do with these things, is you can do a pub sub from anywhere. So we could have a cluster of nodes running. And maybe we have some analytics service running, or for a chat app example, maybe we have some analytic API that's automatically a post to our chat app, some kind of notice. We can do that from anywhere on the cluster and just call a channel broadcast. And then from anywhere on the cluster, that's going to say, anyone listening on the Rooms channel lobby topic, here's some data for you. So you get into some really interesting cases of outside of the user operation, we can automatically be broadcasting events to anyone listening. And I'll show you an example of that. So we'll see if this works. So I have a really high contrast browser window up and running here. Let's see if this works. Yeah, that'll work. So this is a Phoenix chat app that we just saw on the last three sides, other than the HTML. It's exactly what you just saw. To prove that this works, I have two browser windows running. If I say Bob's over here, it works. There's Bob's message in the other tab. Let's push a message from an IEX shell, for example. So from within IEX, this could be, again, any node on the cluster. I could just say, I've alias phoenix.channel to channel here. I could say channel broadcast. Give it a rooms channel. The topic was lobby. And again, this could be any kind of ID from a database. For a real-world use case, you could have anything here that users are subscribed to. And then we give it an event, new message, and then some map. Within here, we're just going to abide by the client contract. They expect a username. So we can say, this is from phoenix. And then the message bodies what the client expects. You can say, hello from IEX. It works. Awesome. So that showed up in the other browser. So again, this could be, we could have an OTP worker running, crunching analytics. And then it receives an event, has some information. It broadcasts it out on a channel. And it just shows up to your browser, to your iPhone, to your smart toaster. So it's pretty cool. All right, so let's look ahead a little bit. What do I want to look at for a phoenix 1.0? I think we want a standard web stack with a real-time layer on top. That's there today. But I don't want to ship a 1.0 too early, because I know Jose and I and the core contributors have been going back and forth on some specific things. So I will say by the end of the year, there will be a 1.0 release. But I won't give any other dates before that. Again, we have routing controllers, views, internationalizations in place now, channels, topics. I'd like an iOS and Android client before 1.0. We have iOS that's pretty close already. And then if anyone has Android experience, I'd love to put a Java client in place before. And then elixir-logger integration is a big thing for us, because if you have WebSocket crashes right now, you get a horribly unformatted error stack trace. So hopefully we can make that better before 1.0. And then I'd like to explore a resource protocol. I didn't get into name routes that are generated from the router for you automatically. But I'd like to see how we're not going to ship a database model layer. I think ECTO is a great choice. But I'd like to see what conventions and protocols we can get in place to allow anyone to bring their own model layer in and still take advantage of being able to generate URLs for a specific database record or ECTO model or what have you. So before 1.0, I'd love to get something like that in place. And then a huge focus for myself is comprehensive guides. I think I've registered phoenixframer.org. It's not up yet. This has already been an issue. Folks are really interested, and they want to get involved. But our documentation needs some work, and we need to focus on the onboarding process. So for the next couple months, one of my big focuses is going to get guides together, whether it's in text form. I think video form works really well for some people. So I'd like to put together some videos on how do you build a chat app, which I have a video of that today. But I'd love to get guides in place. So if you'd like to get involved, we could use guide contributions. And let's look at Beyond Phoenix 1.0. And I have some ambitious goals here. And I'd love feedback, especially. I'd like to focus on distributed services and service and node discovery for a phoenix application on some cluster. And I'll show you what I mean by that. This is inspired by Korea Core. And essentially, it would be a toolkit for easily building fault tolerance services that scale. I don't just mean to say that as a web scale term. I think the Erlang Virtual Machine and Supervision gives us all these great facilities. But we don't really have any awesome framework for building distributed services out and being able to run things in a manner that almost transparently scale for you. And eventually, I'd like it to be a decentralized masterless service registration. But I think it would probably start out as a master slave setup, like our topic layer. Because ReaCore is doing, I think we saw earlier, a process ring where they do consistent hashing. They've solved some really hard problems. And I think I'd like to go that direction eventually. But I'd like to start simple. And I'll show you some pseudocode, what I mean by what I'd like to accomplish. So phoenix service, what is that going to do? I want to be able to spin up a phoenix node. And I want that node to advertise on the cluster saying, hey, I can perform some work. And these are the things I can do. So we're going to review kind of a, let's say we're building a search engine in phoenix. We want to be able to run a couple services like page crawling and page indexing. But those are going to be expensive operations. And we want that to be fault tolerant and also scale out. So I'd like to be able to perform something like this. And I don't want to trivialize this process or what the amount of work that this will take to solve correctly. But this is ultimately what I want to accomplish. So I want to say, anytime we have a node up or a node down, first of all, when you spin your phoenix up, I want to be able to configure a node list for your different environments. So I start a phoenix node, and it's going to automatically find the first node it can connect to and join the cluster. And then notice how we, today you can say mix phoenix start to start your application router. I didn't name that mix phoenix server specifically because I wanted to get into this idea of just starting things with our phoenix app. So I want to be able to mix phoenix start page crawler page indexer on some node, saying I want this node to say, hey, I can crawl pages. I can index pages. And that's going to register itself on the cluster, let all the other nodes know the kind of work I can perform. And what this gives you is it gives you fault tolerance and scalability. And I'll show you the API that I want to do this with. So I want this to happen transparently for you. So this is pseudocode. This is just hopefully to drive the message across. I want to be able to say, def module page crawler, use phoenix service, and then define some commands that my servers can perform. So for the page crawler case, I receive a crawl command to crawl a page. And I want the service to be able to say, you know what, maybe it's busy or maybe it can perform some work. So let's say we have this status function that can take the service as state. And for a page crawler, maybe we can only do 1,000 page crawls at once before we've maxed out IO resources. So this service can say, get your status and perform the crawl. And if your status is busy, so if you've implemented some business logic to say, I have 1,000 page crawls going right now, I'm busy, I want to be able to say, you know what, reply to the caller and say, I'm busy right now, but try the next service. So you'd be running multiple page crawlers on the cluster. And you could return a response saying, you know what, I'm up, I'm online. But hey, try the next one, because I can't respond. Otherwise, you can just delegate out the sum OTP process, OTP worker, a module saying, hey, fetch this page, and then reply, OK, here's the page content. Otherwise, there was some error fetching from the host. And then the great thing, and usually in where the client calls this, is I want to be able to do something like this. I want to be able to say, OK, I want to crawl a page. So service.call, here's the service page crawler. And then here's the command I want to send to it. And what that would do is it would have a node registry saying, find a node on the cluster that could perform that page crawl and do the work for me. And you could get, so let's kind of see how this would work. Let's say it hits the first node and the node says, hey, I'm here, but I'm busy, please try the next one. That service would automatically, for you, find the next node that could do it. That might say it's busy. And let's say the third one running says, OK, here's the page. If we return the page back to you, and you're done. So I want the service, it would find the service for you and also handle busy cases or handoffs transparently. All you do in user land is call service call page crawler. It's going to find a node that can do it and give you a result. You don't care internally on which one it routed to, which ones were busy. You just care about what you get back and that the work was performed. So ultimately, you would get your fault tolerance, because you're going to run these on multiple nodes, and you get scalability. You know that you can do 1,000 page crawls on a node before you max out the IO resources, run 10 of those. And now you've 10 times increased your throughput. So my goal for this is to make distributed services and applications incredibly easy. And this is something, I think, that is lacking in the ecosystem right now. And if you have experience with this, let me know. But I think long, long term, I want someone to be able to bootstrap a Phoenix app with Phoenix New Command and be running a distributed Phoenix application on multiple nodes in 15 minutes. And I think that would let us do that. So that's all I have for today. Please let me know your thoughts. And let's build a future. I think that's why we're all here. And I'd love to build things that I currently can't build with Elixir. Thanks a lot. I noticed in the example code that you have to explicitly HTML safe strings. So when Rails added that, that cut down a lot on the risk of cross-site scripting. So your EX templates, thanks to Eric, are automatically safe for you. So let me bring up a template example. So like in this example here, anytime you would do the interpolated Elixir equals there, that would automatically return a safe string, escape for you automatically. So you don't have to worry about it. The HTML safe system in Rails also annotates that the strings are HTML safe so you don't get double escaping. How do you handle that? So the escaping is going to actually be a tuple of, this string is safe, so it's going to be a tagged tuple of safe value. And if it's a raw string, it's just going to be a raw string. So it's a record? Because that's a tagged tuple. It's actually just a tagged tuple. A tagged tuple as in the first element's an atom and the second thing is your value. OK. And then you kept saying, contract, do you have stuff for EXUnit where you can use them to check that your stuff follows the contract? Yes, so by contract, I just mean plug's contract is you give it a connection and optional argument and it returns you the connection back. OK, so there's no test helpers to ensure that the code is doing that, though? Yeah, you would just write, so plug ships with a test helper library so you can create a connection, pass it through that specific function, and then write whatever unit test you want around that. So whatever the, you inspect the connection after you call the plug, and then you made some assign or redirect it or do whatever you would just test that as you would test anything else. This is awesome, by the way. Thanks, great. So you were talking about automatic service discovery? I soundly open source something that does exactly that. I soundly did so because I've only used it in production for about three weeks. Awesome. But yeah, all the node, it's called discovery. It's on GitHub under Undead Labs' GitHub account. And basically, all the nodes connected is hidden, so they're not fully meshed. It allows you to create distributed federations. And then the messaging layer is not part of it yet. But it puts all the services in a consistent hash ring, and it auto connects OTP nodes together, so you might be able to leverage it. And then the distributed transaction system isn't in there yet, but it exists in my project or set of projects. So we might be able to put that in there as another library that you could leverage that. Yeah, find me after talk because that sounds exactly what I want to accomplish, so it's awesome. So Chris, how is it looking for the community for adding extra packages in here compared to rails for authorization, authentication, active admin, all that stuff? Are you currently building a community around that? Is there any work other than the framework? Yeah, so my goals long term are to have an entire community around Phoenix. I want to create a vibrant ecosystem around it, and I think being plug-based will help us get there. So if you're familiar with Warden from RAC in the Ruby world, someone can implement a plug-in middleware for authentication, and we could just plug it up into Phoenix. So I see a very vibrant ecosystem with plug itself and then also Phoenix, because we'll have a set of shared conventions that will let people do some little bit of metaprogramming if you want to throw in a module, and it could just hook into our own conventions. Because I see one of the biggest barriers right now to actually starting to develop production applications is with all this extra stuff that you'd get with rails. So actually I guess I'm talking to the community here, so I think if we had the community out building this stuff, things would, we'd get into adoption a lot quicker. Yeah, I mean that's the goal. As fast as I can replace my Rails development with Phoenix, I'll do everything I can for that. So I currently have like 10 to 90 some of my elbows and wrists for the amount of typing I've been doing to make that happen. I wasn't trying to lean on you, I was actually trying to. I'm just saying that my goal is, this is, my goal is to do the coding and elixir 100% of my time for both work and play. So as fast as I can make that happen in girl community to help me do that, that's what I'm focusing on. Yeah, Elixir. Yeah. Any other questions? All right, thank you. Thank you.