 All right, well, we're talking about what's next for Phoenix. I should have added a question mark at the end, though, because some of the stuff we'll talk about later is just ideas. But today, really, we'll talk about what the core team and I have been thinking about short-term and then kind of some exciting ideas long-term that it's just kind of formulating right now. So what's next for Phoenix? An immediate future is a programming Phoenix book. It just came out like a day and a half ago. Woo! Yeah. Yeah. It's in beta, so it's a little over half done. And Jose and Bruce and I wrote it. And it's been a lot of fun and I hope to complete it over the next few months, so check that out. And before we get started about where Phoenix is going, I'd like to talk about kind of where it's been. So it's being used in production by dozens of companies. This is just a few. Bleacher Report is probably one of our most notable. They're using it for tens of millions of users. It powers their API, all their web content, mobile content. New startups like Inverse is using Phoenix's core piece of their infrastructure. And we have Dockyard. They believe Phoenix is going to be the best platform for all their client services. And then we have companies like Bullpoker, CargoSense, and OpenDoor, who have been using Phoenix really as a core part of their business and have been absolutely thrilled with it. So there's quite a few more in here and even some bigger companies on the horizon that I can't talk about, but it's really exciting to see. Now that we're at 1.0 and even pre-1.0, how many companies have adopted it and been able to get a ton of benefits out of Elixir and Phoenix? And I want to say from day one, Phoenix has really been about pushing the web forward and kind of evolving with the way the web is going. So it's really exciting to see kind of Phoenix going beyond the browser. And I didn't think we'd get here this quickly, but we have channel clients now for every major platform. So we have JavaScript, obviously, but now we have a Swift and Objective-C client. So we hit Mac OS X and all iOS platforms. Since Justin Schneck is speaking, I think later today, he's gonna talk a lot about channels and have some really exciting demos along these lines, but he was kind enough to open source his Objective-C and C-Sharp channel client libraries. So he brought us iOS support as well as all the Windows platforms. And we have a Java client as well for Android. So we hit really all major platforms now and this is a hard picture to make out, but you can see there's a Apple Watch application, a web browser and a native iOS app, chat application all speaking to the same Phoenix channel server on the back end. So this is really exciting for me for Phoenix really going beyond traditional web development and I can't wait to see the kinds of things that people build with it. So for Phoenix 1.1, small list. And one of these is almost pretty much done. So we wanna add internationalization with the GitText library that Andrea is actually gonna speak a lot about. So I won't speak too much about it. And we get that for free. It's really just about integrating it, but it's a super nice library. And then channel presence is really gonna be what Phoenix 1.1 is all about. And it seems simple, but it's actually a very hard problem to solve and we'll talk about that. But for GitText, it's an existing standard for internationalization. If you were here last year, I spoke about us just landing internationalization, but we ripped it out because it's been a trend, but Jose came to me and was like, hey, we could do this a little bit better. And that is GitText. So I was using a rail style internationalization that I was used to and Jose had done a lot of research and really pitched GitText and it's such a better solution. Because it's an existing standard, we really have existing off-the-shelf tooling for developers and translators. So instead of translators having to deal with YAML files or some esoteric format, they can operate with existing tooling to help translate your application. So it's a better experience for the translators, but it's also a better experience for developers with the talk about. And it's super fast because we can do some neat compile time stuff with Elixir. And Andrea's gonna talk a lot about this. I won't go into any of the details about how the compilation stuff works. But the cool thing about it is this is how you, me typically, coming from a Ruby and Rails background, this is how I would do internationalization. It's like, okay, call some method or function and here's this random key that I've come up with. And the problem with this is we lose the context of what is this welcome message and then is it pages.titles? Is it, are we gonna do a singular convention, page.titles? And usually throughout the lifespan of an app, your team depending on who's working on it just makes up their own conventions and it's a mess. So what GitText says is like, no, we actually just call it GitText and we give it a string of our natural native locale. And by default, if you call this without translating it, it just returns a string. So it's like a zero cost for you to add internationalization support to your application even if you're not planning on internationalizing right away. And when you're ready, you can run a GitText command to do some compile time tricks to generate these files that you can give to your translator and have them translate the application with existing off-the-shelf tooling. So it's a much better experience all around and it's zero cost. And your templates go from this contextless pages.titles.welcome to the actual welcome message. So like I said, it's zero cost. You should use it. You can use it today, but it's not integrated in Phoenix by default. You have to do a little work to get into the view layer. So we just wanna make that easier to integrate. And the big feature for us is a Phoenix presence. And that's really what's on the near-term horizon. That's what I'm gonna focus probably the next few months of my time on. Although hopefully that could be a little sooner depending on how this goes. But at the end of the day, what we really need is folks are trying to solve the same problem. And it's when you have a, let's talk about a chat room. You will have a list of users who are in the chat room. You wanna know when new users join and when new users leave. We don't support that today and folks implement it and usually implement it poorly. And at first, Joe's and I were talking and we were thinking maybe we'll write a blog post. I'm like, here's the proper way to solve channel presence. Maybe we won't implement the feature. And we were like, yeah, that'd be cool. If we could just write like a guide, like here's how you would do it. Just set up some process monitoring, it'd be super easy. And then we got into the details and it turned into a three-hour Skype conversation. And we got nowhere. It was like of all the edge cases, like, oh, but what about this, what about this? And then we were like, yeah, this can't be a blog post. This has to be a feature. And it turns out this is actually a very difficult problem to solve. It's like a classic distributed computing problem. But on the surface it seems simple. Because this is it, on the surface this is all we wanna provide. Like please track my presence, notify everyone that I've joined, maybe have some metadata on what device I'm on so I can show a little icon, like this person's on mobile. And then we wanna get a list of users in this chat room. And then if someone joins or leaves, I wanna receive a message on the client. Hey, this user joined or left. Like that's it. This is like the amount of code. This is all that people wanna be able to do is call this amount of code. But there's a ton of complexity underneath. And this is like exactly the kind of problem that a framework can solve. So you shouldn't have to worry about those edge cases and we wanna solve them for you. But let's talk about the edge cases. So it seems simple and what people do today is they'll have an agent. So they'll just like register an agent under a name. So if we have a chat room, we'll just say, hey, I have a chat room agent that holds who's in this chat room. And then on the join event in their channel, they'll just say, agent, here's a new user. And then they'll say, I can monitor that channel process. And when I detect a channel down event, I'll remove that user from the agent. And that works great on your laptop. It works perfectly. But then as soon as you deploy that on more than one server, it falls apart. Because now you have an agent running on a local node per node. So the view of the world per agent just depends on what users are connected where. So you need to make this kind of a distributed consensus of like, okay, we have different node presences or we have different present servers on different nodes. So let's walk through how this would work. So our nodes are running a present server tracking who's in a chat room. And let's say we have three nodes here. So those nodes need to coordinate some kind of idea of the world and keep that in some kind of consistent state on, okay, who's in this chat room, for my world view. And if someone joins my server, I need to notify the other nodes say, hey, this user's now part of the group. And this is easy because the node present server can use just a simple process monitoring to say, okay, if a channel crashes, it's gonna break the process link. We can detect that. And then we can just broadcast to everyone else over pub sub. Hey, this user left. So this is very simple. This is the easy problem to solve. And this is what Josie and I and I were thinking for the blog post. Like, you just set up a monitor and then you use existing broadcast features on the channel layer and you're done. But all is fine until you have a node down event. So say a node crashes or you're on Heroku and dynos just die or restarted every 24 hours for some reason. And those processes are gonna die obviously with that node, but now the person responsible for broadcasting that those users are gone is gone, the node died. So now you have people in the chat room that are gone, but no one is notified that they're gone. So then you can say, okay, well we could have each, all the other nodes can listen for node down events. And if they detect a node down, then they can be responsible for saying, I'm gonna find the users that were on that node and then all broadcast on their behalf. But then you're gonna have node two and node three both performing that cleanup operation. So what if they both respond to the node down and they broadcast, now you're getting duplicate messages across the cluster on users joining and leaving when really you just wanna have one happen one time. So in a perfect world, we either make sure that they all are eventually consistent with something like CRDTs, like contract conflict-free replicated data types on their different ways we can go with this. But the other day we need to only broadcast the user left over-distributed pub sub from a single place or a single location or have each node only broadcast locally and not on over the whole cluster. So this is actually a very difficult problem to solve and then you can throw in on Heroku, we can't use distributed elixir. So even to get node up and node down events on Heroku, like I had to write a node tracker library that we have to use like Ecto or Redis to recreate like the node gossip protocol or have the dinos heartbeat just to simulate node up and node down events. There's a lot of edge cases to solve here that we know we can solve well, but it's gonna be a matter of making sure that we tackle those edge cases for you. So that was channel presence. It seems like a simple problem and at the end of the day it's gonna be a very simple feature to use but it's very difficult to do yourself. So we're gonna solve for you and I hope I don't wanna give any dates but by the end of the year would be great to have that in place, hopefully sooner. But what I wanna talk about now is the next version of Phoenix. And before I get too far into it, I wanna say that don't take away, if you take away anything, take away the ideas that I talked about here not necessarily the implementation details because we're not quite sure how this is going to look but embrace the ideas, not the specific technologies and implementations that I'm talking about. So what we're looking at is we're inspired by what Facebook is doing with GraphQL. And if you're not familiar with GraphQL, there's been a lot of buzz about it recently. Facebook open sourced it, open sourced they added GraphQL support to react and then they open sourced a GraphQL specification. So GraphQL is actually a language agnostic spec now that you can use anywhere you want. And meanwhile, the same kind of idea has been adopted by Netflix, has a Falcor library that they just released that was developed in parallel to solve very similar problems and they ended up with a similar solution that uses a lot of these same ideas. So GraphQL, it's going to replace traditional client server data requests. So your traditional rest end points would be gone, your traditional ad hoc end points that returned just bags of JSON would be replaced. So it kind of inversed the control where the clients specify the queries, the client has a server, give me the shape of data and it gets returned the exact shape of data that it wants. And a single endpoint would service all data requests is kind of one of the big ideas. And not a Phoenix endpoint, but like you can almost think of like a single controller would service the entire application's data requests in one place, which seems kind of crazy. And GraphQL looks like this. It's a query language, but it really maps to a JSON structure. So it's going to be very similar to the shape of the data that you want from the server to give you. So you could compose a GraphQL query on the left and it's going to map exactly to the key value, JSON response on the right that expects the server to send back. But the nice thing is that the client is going to specify the exact shape of the data that it expects to be able to render its view. And we'll talk about some of the benefits of this. So I have a tweet from Jose here talking about mox and let's, yeah, that's good. And let's talk about, so how would we model this? If let's say we were building, this is good, we're building a REST API for this Twitter post right here. Like how would we do that? We would just have some get request to some status ID. And then we probably return some bag of JSON like this, right, and this would work. This is what the client needs to render that. But then we got to think about some of the issues here. One is if you do this, this is what the client needs, but you end up with problems like, are we over fetching data? Like what if all of our API clients don't need the user's profile picture? Now we're doing a join and having more complex work on the back end, also putting more data on the wire for data that we're going to throw away for particular clients. So we have potential for data over fetching. And there's an implicit contract back and forth on, the client does just a get to a status ID and then there's just an arbitrary JSON payload that just expects to look this way. So you would hopefully maybe document this somewhere in your API, but there's an implicit contract there. And then you get into issues like, what do you do about replies? If you're just going to a webpage with that tweet, maybe you don't need replies. So what do you do? It's like, well you can include them by default, but then we're over fetching data. Or you can say, well, we can just add a bunch of query string parameters, right? And if we get the replies, then we can just add a bunch of nested query string parameters and we have like a, the JSON API spec kind of formalizes this to solve some of the similar problems here. But the problem is you end up with like a query language as query string parameters, doesn't compose very nicely and you still have this implicit contract. So this is what Facebook was having issues with their applications, where they had this implicit contract going back and forth. They were often over fetching data, or worst case they were under fetching data where they needed data that the server didn't send in these arbitrary payloads and then the client would have errors. Or if you're using AngularJS, you end up with like the bracket, bracket variable name, like you see in some applications. So the solution that Facebook came up with was, the client actually is going to specify to the GraphQL server, here's the exact shape of the data that I want. And it's gonna get the response of that exact shape back. So if it needs the user's favorite account, it's gonna ask for that field. If it needs the profile picture, it's gonna ask for it. And then if it needs the replies, or if it doesn't need the replies, it wouldn't ask for them, it wouldn't receive them. And if it does, you could even say, give me the first send replies, but I only want the text and then the user's name. So you are able to get the exact shape of the data that you require to fulfill your rendering needs. And that's a big idea behind GraphQL. But if we look at Phoenix, like how does this apply to Phoenix, right? I'm not asking everyone to become a JavaScript developer and use React.js. Let's see how about how these same problems affect Phoenix today. We have some implicit view data requirements. The same issue that Facebook had with their React.js templates and data having this implicit contract with the server. We have the same problem today. Let's say we wanna render that tweet that we just showed. Well, we would start off very simply, the template would say, okay, show the tweet's text. And then this would render. If you're using Live Reload, it would just show up like magic. And this would work. And then someone says, wow, we need to spice this up a little bit. Let's show the tweet's username. And then like this would explode with the Ecto Association not loaded error. And you'd say like, ah, okay, well, let me go back to the controller and like, okay, get the status but preload the user and then boom, it would work. And this is a good thing. So this is a pain point that we have but a lot of languages solve this pain point by saying, well, status.user could just be lazy and we would just do a query lazily and then fetch that user. But the problem is we want our view layer to be pure because you're not pushing off the complexity to rendering a view. And then you end up having to just do much of fragment caching. And really you lose any kind of idea about the complexity or the cost of rendering. You just hope that it's fast and then you see the response time start to become slow and you just start wrapping cache functions all throughout your templates. So the solution is not to make this stuff lazy, the solution is let's find a better approach. And it just gets worse. So let's say you do that and then someone else says, let's show the user's profile picture URL. This is gonna explode with the Ecto Association not loaded error. And now you have to say, okay, let me go to the controller but this might be in some partial template. So you have to say, let me go to the parents, let me go to the parent template and make sure it passes the correct data in first. And then it's still gonna blow up the Ecto not association loaded error. And then let me go to every place that I have to fetch in the controller or a mailer and then say, okay, now preload the user's profile. And then it just continues. We wanna show the replies. Well, it's gonna blow up the Ecto Association not loaded error. And then we have to preload the replies but then we want to preload those replies user profile picture. So you end up with this same pain point that Facebook had. It's not as painful because it's in the same code base, to the proximity, there's no context switching but we still, you can see how much churn is happening in the code base to get around this problem. And then anytime you change a template you have really no idea am I breaking the code in the controller? You have no clue. You have to change a template and then live reload refreshes. And if you see an error and then you're like, okay, it broke somewhere. You have to go track it down. So we wanna figure out, how can we embrace some of these ideas that Facebook has used to solve client problems but would bring them to the server. But we also have this issue today of controller mayhem. So if we're building REST APIs we can use things like the JSON API spec to kind of help with some of this. So this is gonna be kind of a contrived example but I've been in applications professionally that look very much like this. So let's say we're building Twitter and our native app is gonna do a REST request for some tweet and now we wanna have a browser maybe doing a request for some users favorites. So all's fine until we wanna change the payload structure of the data that we return when we show a tweet. Well, since we have a native app that's running a JavaScript environment, we can't change that code. So it's like, well, let's just version. We have a new version of the API and the browser can get new JavaScript so we'll update that. So that works but then you're like, ah, but sometimes my favorites need the replies. So then I'll just build an ad hoc endpoint here and boom, it works and the client, they get the exact data that they request and then you're like, ah, shoot, Apple just released an even bigger iPhone and now pixels are doubled yet again. So now we go back to our now deprecated API and we add like a clear stream parameter and now you can get a pixel doubled profile picture and like this is like applications turned into this, right? So this is another pain point that GraphQL solves because it just gets rid of all that. It just becomes every client talks to the GraphQL server and gives a request saying this is the shape of the data that I require. I know you can provide this capability. Please give me the response back the way I want it. And we don't wanna just make a big bet on specific technologies but we do think that queries being specified in a client rather than the server is actually a very interesting idea. And since Facebook has been using this in production for two and a half years now, they have great tooling around GraphQL. So they have tooling around being able to be able to introspect a GraphQL server so you can just have a web application that talks to the GraphQL server and it lists like here's all the capabilities, here's all the data that you can request. It generates documentation for you automatically. You can actually embed documentation in the GraphQL queries and servers itself. So it kind of bars from this idea or embraces the idea that we have an elixir of like documentation as first class. It's gonna validate your queries so you can explore different queries and you can encode declarations in the GraphQL server. So clients can actually be notified in development. I'm now calling a deprecated field or a deprecated specific endpoint to GraphQL. So there's some really nice tooling built around these ideas that Facebook has put out. And I wanna reiterate that GraphQL is a server and language agnostic. So don't think that this is just like targeted at ReactJS. This is GraphQL as a specification that is server and language agnostic. So now I'm gonna show a ReactJS template but just keep in mind that the ideas that I am presenting here, not that you have to write ReactJS applications. Although I do like ReactJS quite a bit. So this is going to be a, this is a ReactJS component. And the big idea Facebook had is they wanna say, for this template at the bottom here, we have a div, we're gonna render a profile picture. We wanna say, we wanna co-locate the data requirements, co-locate the query with the template and view that's rendering them. So right alongside the template that we're rendering, we can say, okay, here's a GraphQL query. I wanna tweet, give me the tweet's user, and then I'm going to compose that with another component's profile picture. So that's going to be responsible for giving me the fields that the profile picture needs. So you can actually compose queries that live alongside the components that are rendering them. So it gets around this case of like, do I have the data from the server that I need? Well, you look at the query and you say, no, I don't. If you're rendering the profile picture here at the bottom, you look up and you say, I'm not pitching the profile picture. Let me add that line to the GraphQL query, and then suddenly the server returns it. So you get the exact data that you asked for back, nothing more, nothing less. So this gives you some really nice benefits. One is we get declarative data requirements. So we get kind of explicit data requirements. It jives well with the kind of things we hold near and dear in Elixir, right? You get a single server endpoint to service all requests. So this gives you some nice ability to do like batching of queries. So the client can actually batch these GraphQL queries up and send them all to the GraphQL server in a batch at once and get the data back. So you get some really easy optimization wins. We get one-way reactive data flow coming out of ReactJS component ideas and co-located queries. So the queries live next to the views that rely on them. So we get rid of that churn going back and forth of this implicit contracts. And things compose really well. So you have composition of components so you can share the queries. If I'm rendering, like I mentioned that, if I'm running a partial of the user's profile picture, that partial view would specify the data that it requires. I no longer have to chase down the parent render chain to figure out, OK, I need to pass this data in up three levels. And another big win, we can get caching for free out of this. We can specify, if we specify the exact shape of the data that we want, we can build a cache key for that. And we give you caching for free. So there's some really big wins with this approach. And at this point, you're probably thinking, like, see, is Chris asking me to start writing React.js applications, even though he's promised he's not. I'm not. But it's only because this is the decision you've had to make for the last several years, where a lot of what Bruce talked about, we have these increasingly popular demands of our applications need to be richer and richer, more interactive. So you have to make a big bet when you start your application, like, are we going to go a JavaScript single page app, or are we going to render a server HTML? And you have to live with this decision forever. Or you, in worst case, have to make the choice of let's do both, which is horrible. Looks like this, right? It's like, well, we can do that. We'll use React.js, we'll use Ember, we'll use Backbone, knockout, I don't know, Angular 1. But then you rewrite it two years later. Surprise, and Angular 2. And then we have native apps to support. So let's just do JSON controllers. And then we still want to use HTML because the web's great at what the web's doing. Like, we want to implement back buttons. So cool, we'll just implement them both, or we'll build it on one or the other. So we want to get rid of that. And that's what excites us about some of these ideas. Well, I haven't told you how yet, so good, yeah. Cool, yeah. But that's what's exciting about this. So we talked about, let me just recap, like, what we want is declarative data requirements for our Phoenix applications. We want one-way reactive data flow. We like the idea of collocated queries. We like composition, function composition is a good thing, and we want caching. So the idea is, what if we just had all that with a Phoenix view plus the ideas of GraphQL? And that's really where we want to explore. The big idea is, what if we could treat server-side views as just another GraphQL client? Because at the end of the day, we can have a GraphQL server up and running. If you're building a JavaScript application, it has to go over the wire. But what if we were rendering Elixir Phoenix views, but they were just talking to the GraphQL server, which is just a process running in our Elixir application? So that's a big idea. Is, let's say you have a native application, and you have a React.js app, or maybe Ember ads, GraphQL supports. Those are talking to a GraphQL server. And then you say, our Phoenix view layer is also just going to talk to this GraphQL server. And that holds all of the data demands and data capabilities of the entire application, regardless of platform. So kind of the same idea, like Phoenix channels, where we want to service multiple platforms from one back end. And it could look something like this. I have no idea, but GraphQL, unfortunately, today is specified with string interpolation. So we could try to build maybe a DSL on top of that. But this is just basically ported from the React example. We could have a Phoenix view, which is an Elixir application rendering EX. And at the bottom here, we have this SIGLE-E. I'm not recommending people stop writing EX templates in separate text files, but a SIGLE-E today is actually a thing if you didn't know that. And Phoenix template today, you could define a function with SIGLE-E, and then it would just precompile that into an EX function body. So this is just a shorthand way for me to keep this on one screen. So render could be a separate template dot EX, dot HTML dot EX. But the idea is to take the same ideas that we had in React and say, let's compose this query. And what are we rendering? It's like, well, we're rendering our tweet, but then we want to compose a profile picture view that has its own data demands. Well, we could just specify a query to the GraphQL server and get the exact shape of the data that we need. So now we've collocated the queries. We could build a cache key for this, and we could even do some computation at compile time to not have to worry about mucking with the string. So at runtime, we've got our GraphQL AST just ready to go to the GraphQL server. And then, longer term, I'd like to see if we can actually run these components as processes on the server. And this is way longer term, so keep in mind. But one of the crazy ideas is, since we can render this on the server, what if you ran this as a process, subscribing to data demands? And anytime the data changed on the server, you could actually re-render on the server. You could think of this as a virtual DOM on the server. The idea with React.js is they had a virtual DOM. Anytime anything changed, they computed the diff and updated the DOM for only the elements that changed. So what if we could render this on the server anytime the data changed, compute that diff, so we're doing a minimal computation, and then we put minimal data back on the wire, and we could update the browser in real time automatically, anytime any data changed on the server. So there's some even further off ideas that could be really cool around this idea of using some React.js ideas. And if you're not sold yet, I want to say that GraphQL or approaches like it is naturally parallelizable. This is another thing when Facebook was talking about and presenting this that really excited me. So this is like a real world example of, let's say I'm showing my Twitter profile. To show that, I'm probably going to need to fetch my last four photos that I posted. Usually when you post a photo on Twitter, you have to attach it to a tweet, so I want that text so I can show a caption on the photo. I want my profile, give me a location. I probably pinned a tweet, so get the pin tweet, get the text of that, and then also give me the last 10 tweets that you posted. But if you look at this, even with SQL, these are all going to be separate queries. We're going to have to hit the actual repo. There's no way around it. If you're using standard controllers today, you could write a bunch of queries. But then you'd have to say, OK, I need to wrap all these in tasks.asyncs, and then do a task of weight before I render. And that's totally fine. Elixir makes that actually super easy. But wouldn't it be nice if you could just write the repo.allrepo.gits and then the GraphQL server would just parallelize these automatically for you? Because if you look in the shape of the data, it would know what it can parallelize and what it can't. And it would automatically run these in parallel for you, just based on the client data requirements. So that's one of the really cool ideas behind the GraphQL spec. But I will say that one of the first questions that came up when we were talking about this with the core team is, couldn't we just do this with EctoQueeries? Do we need yet another query syntax? Wouldn't it be nice to colloquate EctoQueeries alongside our templates, and then we don't have yet another query language to support? And that's a valid question. And that's a direction that we could go. So right now is just looking at these ideas. And whether or not it's fully GraphQL, or just embracing the ideas, or maybe a partial GraphQL implementation, we're not sure. But we really like the ideas behind GraphQL. It has really great backing from Facebook. It has really great tooling built around it already. And we see some really, really nice benefits. And if you happen to be using ReactJS, one of the coolest things is, let's say I built a fully PhoenixVue server rendered HTML application. And then I wanted to write a ReactJS application, or a React Native application. I could just do that and have it talk to the GraphQL server, and I would not touch the back end code, and my application's done. I've exposed the data requirements already just to render HTML, and suddenly ReactJS, or React Native, or any other application that supports GraphQL would just work out of the box. So now we have a single endpoint to scope our queries, our authorization, and we can do it in parallel. So that's the ideas for Phoenix next, right? We're going to embrace the ideas. Maybe that's GraphQL wholeheartedly. Maybe it's just the ideas, and we implement it partially. But at the end of the day, what we want is declarative data requirements, collocated queries with our views, automatic caching, and query parallelization. So for my first step after Phoenix Presence, I want to experiment with a GraphQL server and really play some of these ideas and see where it goes. So that's it. That's all I have. And let me know what you think.