 From Rails to Phoenix, why Phoenix? When we hear about Phoenix, we hear about performance. This is what most people, when they first install Phoenix, they're blown away at the average response times that they're seeing. It's a common thing to see almost daily a new developer tweeting out their delight in sub-1 millisecond response times. Some have even never seen the U symbol in the logger before. So it's a great hook for those looking for something much faster than Rails. But we have to ask ourselves, is performance enough? Can you go to your boss and say, this other framework is much faster, so we need to rewrite everything in? Do people, your users, even care about the performance once you're past a certain threshold? Let's look at one guy's opinion. So recently, David was on a podcast talking about Rails performance, and he said, I see a lot of hello world benchmarks that respond in nanoseconds. Who gives a flying F? Have you ever met a customer who said, your page rendered in 100 milliseconds? That is not good enough. I need nanoseconds. No one ever asks for that. I think his DHH is right. He's absolutely right. None of our customers are complaining if our page renders in 100 milliseconds instead of 50 milliseconds, or 200 milliseconds instead of 100 milliseconds. So the question is, isn't who wants some 100 millisecond response times? Real question is, how difficult is it for your engineering team to achieve that performance on a consistent basis? How much effort is required to reach this threshold? Let's take a look at a real world example. So if you're unfamiliar with Bleacher Report, they are a sports news website, and they were running Rails for a very long time. They had, in the summer of 2014, they began a rewrite in Phoenix. They were probably one of the first large commercial websites to actually do so. And at that time, it could have been considered a legacy Rails app, pretty decent size, 50 models, 40 controllers. The characteristics of their production environment prior to the rewrite was 150 AWS instances. Their responses were log jamming, and by that, we mean their response times were taking so long that as new requests are coming in, the responses were not coming out fast enough, and so the application server would fall over. Multiple engineers per application, and multiple complex caching strategies were in place. Afterwards, the results of the rewrite after they went to production with Phoenix, one-fifteenth of the servers previously required, 10 to 30 millisecond response times on average, largest average spike 400 milliseconds, and there's been only one instance of a spike ever reaching up to 800 milliseconds. These applications are supported by about one engineer per application, and there's no caching in place. So you may be asking, how is this possible? Well, as Rails developers, we are told two things. Well, first of all, we're told that we should make a sacrifice of performance for productivity, but beyond that, we're also told that we should call the database as little as possible, and we should render from the cache as much as possible. Using the cord, the creator of Phoenix is seeing more and more reports coming in of applications that have made the switch from Rails to Phoenix and seeing as fast or faster response times without any caching in place. Others have seen the same and share the story. And it's not just Rails. There are many other languages and frameworks that suffer from cacheitis that Phoenix has been able to alleviate. How can this be? Why is Phoenix faster in some cases without caching than other solutions with caching? This doesn't make sense to most people, it doesn't compete. Elixir is a concurrent language. Instead of objects passing messages between each other, like you have in Ruby, you'll have many independent running processes running that are passing messages. Elixir runs the Erlang VM, also known as the Beam, which manages its own processes. So unlike operating system processes that start close to one megabyte in size, the processes in Elixir are far smaller, usually weighing in around one kilobyte. In addition, they are all isolated for another and they each have their own garbage collector. So while the total number of objects to be collected may be similar to a Rails application, in a Phoenix app, any given garbage collection is limited to its own process instead of running on the entire world. This means the collection ends faster and it runs on much fewer objects. To facilitate all these processes, Erlang is a language that Elixir has built on top of. Erlang consumes as many cores as possible in the CPU, whereas Ruby was built and is still meant for a single core world. Elixir being a compiled language means that Phoenix can push a lot of the work to compile time that Rails has to do at runtime. An example of this is the Phoenix router. So in Phoenix you have a system called Plug, which is a base library, and Plug provides functionality similar to Rack in that you build out these middlewares. And during compile time, Phoenix will actually compile different paths that the middleware can take, whereas in Rails this has to be negotiated at runtime. Phoenix makes really smart use of the Erlang VM, let's see an example of this. In a blog post recently written by Evan Miller, in this post Evan describes certain tricks Phoenix uses to enable extremely fast template compilation. The TLDR of this is other languages will delete and create new strings all the time during template compilation, whereas Phoenix makes use of Erlang's IO data type that allows for memory reuse. And finally, the database is not as slow as we've been led to believe. The idea that the database is a bottleneck is all too common misconception. Here we see Chris warning that one shouldn't fall into that track. And Parker Selbert recently wrote a blog post talking about this. Back in February, he built two APIs, one in Rails and the other in Phoenix. The Rails API was built with Ruby 2.3, Rails 4.2, had Redis cache, and using active model serializers, had a warm cache built, warmed up the cache before the benchmarks ran. Tune the fetch to as little data as possible from the database, all associations are preloaded, all content is cached as strings, no marshling, so you get the highest performance. All data is generic, not customized to the current user. That means that they're benchmarking against different users in the application, and we don't want to get a custom one every single time that's going to bust the cache. Request is paginated to 100 primary records without a limit on side loads, and finally the payload for the Rails side of things weighed in at 160K. On the Phoenix side, latest, Lixar, and Phoenix, no entity cache. Fields are fetched from the database, so every request is hidden in the database. All JSON responses are serialized on the fly directly in views, includes customized data based on the current user, so unlike the Rails application, this is actually building out responses based upon user's customized data. The request isn't paginated at all, there are 250 primary records, so we're getting more data coming back, and the payload is 724K. The results of this is that the Phoenix application is serving up two and a half times more records with four and a half times more data in those records. Without any caching, the Phoenix API response times are on average one and a half to two and a half times faster. Why does this matter? To better understand that, let's take a look back at the Bleacher Report results. Phoenix doesn't ask you to compromise performance and productivity. In fact, because of its performance, you could argue engineers will be more productive. When it takes less people to support a similarly functioning application, those resources can be put to better use. Instead of putting out performance fires or having to manage a complex caching graph, the engineers can focus on features. No matter how you spin it, not working on caching is always going to be faster, it's always going to be less work than having to work on caching. So the question is, can Phoenix's performance benefits free engineers to work on bigger ideas? So to help us answer this question, I think we have to look back. And the question right now isn't why Phoenix, why Rails. And I don't mean to say this as a hit on Rails, just the opposite. I owe my career to Rails. I think a lot of people in this room owe their career to Rails, and Rails has changed many people's lives. Instead, this is more taking a look at what made Rails popular in the first place when it first came about. To me, the reason Rails did so well is because it had two very compelling stories. First, it allowed you to build something in half the time for half the cost. Second, it optimized for developer happiness. So the business people were happy that they're spending less time and less money to get their product out there. And the engineers were happy that they get to work in a language and a framework that they actually liked. I've spent some time already talking about how Phoenix can be more economical to build out, so let's focus on this. This is what we're taught from day one as Ruby developers. Ruby optimizes for developer happiness. In Rails, piggybacks on that. I want to challenge it. Does it actually do that? While the Ruby you write today feels good, what about the Ruby you wrote last year? Does that feel good? You go back and read it, you go back and use it? About last month, about last week. Is the idea of going back and looking at code that you previously wrote make you happy? The true problem, sorry, this is a very common complaint in main languages. But it boils down to a comment on the language features rather than any syntax. The true problem is state. We spend all this time building up state in our heads. Having to construct this complex system in order to understand how even the most simple of code changes affect anything else. Imperative programming languages like Ruby that allow for the state of the entire application to be changed anywhere else requires more time to reason about it. So when you're making changes to code you've written in the past, you're dealing with having to recall from memory that application state. And how other methods in the system could affect that state. Reading other people's old code only completes the complexity and makes people more angry. Which could really explain why we hate reading other people's old code. Lixar has an antidote to this. It's called functional programming. Now, functional programming is not a magic wand. And many people still see the lambda and they get scared because math. But let's see how simple functional programming can actually be. Does everyone understand that the result of this would be three? Congratulations, you're a functional programmer. It's not that simple, though, in reality. Some traits of functional programming in Lixar are that functions are pure. By saying functions are pure, this is a big concept to understand. We mean that functions don't have any side effects. So in Ruby, you may be modifying instance variables or global variables or something else outside of the function itself. Whereas in Lixar, you have data coming in, you have data going out, and there's no other effects outside of that contract. Variables are immutable. So in a distributed system or we're learning concurrent processes, having to deal with what the values are in the variables that you previously read could lead to race conditions. And immutable data is just something that helps alleviate that from the get go. And finally, explicit is greater than implicit. This is kind of the, in Ruby and Rails, we say convention over configuration. And Phoenix definitely subscribes to convention over configuration. But in Lixar, you hear quite a bit of explicit is greater than implicit. An example that could be active record callbacks. So if you go back and read someone else's code that's calling save, you don't know what other 50 things could be happening. Whereas in Lixar, you're gonna have a very explicit code path that things are taking, it's not, you don't have to go code splonking. You don't have to find out where the effects are taking place. So all this results in a system that allows you to do more happy. Simpler systems are easier to hold in your head. Documentation is easier to find. You don't have to figure out, okay, what class is this instance part of? And code is much easier to test. When building Elixar, Joseph Villeen had the opportunity to learn from other languages. He took what he saw as some of the best features of other languages and put them in Elixar. He took the syntax from Ruby. He took the pipe operator from Fshark. If you're unfamiliar with the pipe operator, let me introduce it to you. So writing deeply nested function calls like this is not unheard of, but it's also very difficult to read. So you may break it up like this. Pipe operator simplifies it even further. So the idea here is that the previously, the result of the previous statement is now injected as the first argument in the corresponding function. So Baz takes QUX as its first argument. Result of Baz is now piped in as the first argument of bar and so on. The reason why this ends up being really nice is Elixar also cleans up a lot of Erlang code. So Erlang doesn't have the pipe operator. And what would be considered to be the primary argument is not really consistent in its arity, in this place within the function arity of the Erlang standard library. So Elixar had the opportunity to actually wrap all these Erlang functions and have a discussion over, okay, we expect perhaps this list to be the primary argument. And so we're going to always assume that it's going to be the first argument here, which plays in really nicely into the pipe operator. Pattern matching is something that was already in Erlang. But if you're unfamiliar with the concept, it's not regular expression pattern matching. Pattern matching has to do with function definition. So here we see three functions that are defined. They all have the same name. They all have the same arity. You can have different arity when it comes to pattern matching or rather function definitions in general in Elixar. But the difference here is the first argument. So for the first function, we see 0, 1, and x. And in this imaginary contrived example, we're going to pretend that multiplication is super slow. And we've optimized that quite a bit. So what ends up happening internally, if you call a function with 0 as the first argument, it will match back to this function. And it will give us whatever result we put in. If you have 2 as the first argument, it matches back to the bottom one because the bottom one has a greedy matcher in a variable name. Where this comes into play, it ends up being really nice, is a place, for example, in Phoenix controller actions. This is a simple action. The URL params are passed in as the last argument. But what if you had a query param that you wanted to work with? In other languages, you may have some ugly conditional statement inside the function. Or you may have some other way to parse it out at some point during the request cycle. In Elixar, we can pattern match directly up here. We can just grab it out. So now we can work directly with the query object. And we can still work with the original params object. So the value of whatever was assigned to the query. This is called a map that the second argument would be used to have called hashes and Ruby. But what's assigned to the Q key is now bound to the query variable. And then the entire map is bound to the params variable. It doesn't stop there. We can even match on specific values within the map. Top function will match if Q is equal to bar. And now we have a very specialized function to handle that parameter. By learning what has worked in other languages, by making the best use of Erlang to avoid having to write caching strategies until absolutely necessary, Elixar and Phoenix optimize for your long term happiness. But how different is it working with Phoenix from the perspective of a Rails developer? Let's compare the two frameworks on a very high level. Here's a Rails application structure. Phoenix application structure. Primary difference is going to be instead of app, things live in web. Rails router, Phoenix router, Rails controller, Phoenix controller, Rails migration, Phoenix migration, Rails generator, Phoenix generator. Elixar also implemented tooling that should be familiar to Ruby developers. Rake and Bundler are represented by the tool called Mix in Elixar. Mix is also a first class citizen. It's built into the language. Other tools like IRB, Ruby Debug, and Pry are also represented natively in Elixar. IEX, the Erlang debugger, and Pry is part of IEX. In fact, most other tools in services or libraries that you may go and use outside of Rails are built into Elixar. It's leveraging everything that's in Erlang. So Phoenix was inspired by Rails. And Elixar was inspired by Ruby. And you may be convinced of this, that Elixar is Ruby for Erlang, and that Phoenix is Rails for Elixar. But Elixar is not Ruby. Phoenix is not Rails. Chris wrote a blog post specifically on this. He acknowledged the similarities between the frameworks, which have been discussed as where the two diverge. And if you're interested in knowing that, suggest you go check it out, because it's on my company's blog. We'll do the marketing right there. This is evidenced by my feeling that the least interesting part of Phoenix is actually the performance story. That may seem strange considering all the performance numbers that I've already shown you. Now Rails changed the world. The past decade, in my opinion, would have been very different for startups and tech companies if Rails didn't exist. Most startups that they weren't using Rails, they were likely using something inspired by Rails. And every day we're met with another comment on how the sky is falling, on how startup investment is drying up. This quote is actually, I think from about two years ago, or three years ago, the CEO, former CEO of Yammer. He, after Yammer IPO'd, he pretty much just pieced out and said, that's it, that's the last idea. I just cashed in, see you guys later. And Mark Andreessen weighed in and said, that's nonsense. There are infinite number of great ideas out there. But how do we facilitate? How do we enable those ideas to come about? I believe that technology is the lens through which ideas are grown. How do we expect to find the next big thing if our lens hasn't changed in 10 years? Phoenix enables us to think about how we built software in a very different way than we built in Rails. OTP, you can think about that as a standard library for building distributed applications. It's part of Erlang. It's been there for, I think, close to 20 years at this point. And Phoenix itself is a distributed application. Some people may be confused about that. When you think about Rails, you think about the monolith. And it's at the top of the pyramid. But in reality, within the Elixir Erlang ecosystem, Phoenix, while it may seem like a big thing, it's actually just can play a much smaller role and a supportive role amongst a wider system of applications that are running alongside and next to one another. So by leveraging the best that OTP brings to the table, Phoenix is solving incredibly difficult problems. A little while ago, Chris decided to test how far he could push Phoenix by scaling up its WebSocket connections. After a few performance tweaks to the framework, he was able to get two million concurrent connections over WebSockets with a single Phoenix application instance. Now it was a very beefy box. Had a lot of RAM, had a lot of cores, but even still just one application instance was pushing this. There weren't any empty connections running. All the connections were simulating, chatting across the network. And a broadcast to all of the nodes took under two seconds. So Phoenix continuing to push the boundaries on what is possible was so little allows us to dream up a different class of applications that were only achievable under, by multi-billion dollar companies in the past. This is the same leap forward that Rails gave us when it first came about 10 years ago. Recently, Chris's focus has been on Phoenix 1.2, which will come with a new feature called Phoenix Presence. Presence allows it to solve a problem amongst connections that's supposed to be unique, but may be coming from different areas. So imagine a situation where you join the same chat channel under the same account, but from different devices. And what if that chat is being facilitated by multiple servers? So you may join, there may be a net split, and then you join server A, and on the other device you join server B, and then there's a conversation going on amongst the isolated between the two servers and when they join back up in the network, how do you resolve the differences at that point? This is an incredibly, insanely difficult distributed programming problem to solve. And Phoenix is going to give this to you out of the box for free. 1.2 I believe is due out in a few weeks or release candidate right now. So, how do you learn Phoenix? Nice thing is that as Rails developers, you already have a huge head start over everybody else. We went through this at Dockyard. We had a client application. We were actually rewriting it from there. And I was the lead developer on it, but we basically were running out of time so we wanted to put more engineers on it. All of our engineers had, were trained up on Rails. So I gave them, gave Thomas' programmatic programmers book, programming Elixir. And I said, read part one. Part one is about 200 pages. It goes over Elixir syntax, basic functional programming. And after about a week, they had enough knowledge that they can start making meaningful contributions back to a Phoenix application. Now that's not to say that they were expert Elixir developers. They weren't Elixir Phoenix developers. They weren't expert distributed application developers. But Phoenix is so similar on its face that if you are already familiar with an MVC framework like Rails, then you're going to have a much easier time transitioning to it. And this is a huge value proposition for companies that may be concerned about adopting Phoenix, right? So the concern is always, we agree it's really cool technology, but who's going to build it? Who's going to maintain it? Well, there you go. It takes about a week to retrain a Rails team in order to work with Phoenix. And this wasn't just our experience. We've seen a lot of other companies, a lot of other people mentioned similar experiences. So some reading material if you're interested. There's some really good books out there on Phoenix and Elixir. The middle one, Sasa Yurik, if you want a more advanced introduction to the books, Elixir and Action. Programming Phoenix just came out. It just reached publication with Chris McCord and Joseph Villeen and Bruce Tate writing it. And finally, Elixir for the Rubyist is not out yet, it's under development by Hal Fulton. So two of these names on the list may seem familiar. The economics and Hal Fulton, also known as the authors of the programming Ruby or Pickaxe book in the Ruby way. I think there's something here where the authors of two of the books that were most responsible for evangelizing Ruby are now evangelizing Elixir. In closing, let's go over how we've answered this question. Why Phoenix? You can offer an order of magnitude and performance. You can avoid having to wrap all your coding caching, implementing features costs less money, requires less engineering support, optimizes for long-term developer happiness, takes about a week to retrain existing real developers. And it's going to change the world. So thank you very much. My name is Brian Carderola. I'm the CEO of Dockyard. And if you're interested in working with Elixir and working with Phoenix, please come and chat with us. Chris McCord, the creator of the framework works for us. We hired him about five months ago to work on Phoenix full-time. So thank you guys very, very much.