 Welcome to my talk. I'm gonna talk about the Phoenix Framework today. My name is Christian Cook. I'm from NCSA in Chicago. So I've got a couple few goals for today's talk. I wanna familiarize you with the Phoenix Framework generally, and I also hope to root our discussion of the Phoenix Framework in terms of Phoenix, Elixir, OTP, and Erlang. So we'll sort of explain some of those in a minute here. So what this talk is not? No Phoenix puns. I'm very sorry. No memes. And you're a smart RailsConf crowd. I certainly don't need to pander to you by showing you pictures of my cats because that would just insult you. So why not Rails? Sort of reasonable question to ask at RailsConf. I didn't come here to tell you to blow up your Rails apps. I'm not an evangelist kind of guy. Rails is great and I enjoy working with it. I know it very well. It's fast to deliver functionality. It's fast to develop. However, I don't really love trying to grow my Rails apps. It usually requires more than just spinning up additional servers and it often requires new technology in the stack. Redis, Sidekick, another queue agent, maybe Elasticsearch, something like that. So let's consider one alternative. The Phoenix Framework bears a lot of similarities to Rails and shares many of the same motivations. Chris McCord was a Rails programmer before writing the Phoenix Framework. There are many aesthetic and structural similarities between Rails and Phoenix. Both are designed to be productive frameworks. Both emphasize convention over configuration and both are server-side MVC frameworks. There are also a number of important differences. Phoenix is written in Elixir, which is a functional language. A Phoenix app is compiled and a Phoenix app isn't really an app at all. It's an implementation of an OTP application written in Elixir. So I may use Elixir and Phoenix a little bit interchangeably today. In part, this is because the Phoenix Framework is the implementation of an app written in Elixir and by design, Phoenix programming is Elixir programming. Yes, I will. That's next slide. Two slides from now. So Phoenix Framework is a web framework written in Elixir. Which is a functional language that grew out of Erlang. So let's look at what each of those components implies. Functional programming offers data immutability, meaning actions taken on data structures always return a copy of a new data structure while leaving the original unchanged. There are no objects or classes. Instead, you pass data like hashes and arrays to functions, which are first-class elements. So Erlang is a programming language used to build scalable, soft, real-time systems with requirements on high availability. It was originally developed by Ericsson to support their telecom infrastructure. And the fault tolerance required to seamlessly failover from one switch to another makes Erlang an ideal choice for use in the web. Erlang has a somewhat different syntax that bears some similarity to Prolog. And it's used by a number of companies in production, Ericsson, since they developed it sort of obviously. WhatsApp, another one of the more common, more well-known companies running Erlang. The OTP, to your question, is the open telecom protocol, which I've also heard defined as the open telephony protocol. But basically, it's not quite a full-fledged framework. It's more a collection of Erlang libraries and design choices that will create applications that conform to and offer a distributed, highly-available, supervised, and failure-resistant runtime. So Elixir is a dynamic functional language that has a syntax that's somewhat similar to Ruby. It was written by Jose Vadim from Platform Attack. He was previously a member of the Rails core team. Elixir offers the promise of building distributed, scalable, maintainable applications that can run with very low processor overhead as well as very low latency. Why Phoenix? Because Phoenix is written in Elixir, which is written for the Erlang virtual machine, it's a functional, immutable, asynchronous, scalable, lightweight, and fast. A Phoenix app is compiled with the added certainty that that can provide around runtime stability, and it's well-suited to the current state of the web with multi-core processors running multiple processes on a single machine or many machines distributed geographically. So there are a number of companies who are running Phoenix in production. Bleacher Report is the one, the example I've heard more. According to their reports, they were able to handle eight times more traffic while reducing the number of servers when they migrated from a Rails stack to a Phoenix stack from 150 servers to five. And if I'm honest, that sounds a bit too good to be true. And there's probably a little fudge room in there. Maybe they dropped a Redis server or something like that, but anyway. So that's enough talking about programming languages. Let's look at an example. So here we have a Ruby example. We define a class and a class method to modify a hash at a given key by adding the third argument to the initial value. When we evaluate it, it does pretty much what we expect, except we will note that our original hash and our new hash both have the same value, and if you looked at the object ID of the two, they'd be the same object ID. So let's write the same thing in Elixir. Instead of a class, we're gonna define a module, and we define a function within that module. Because a module is just a group of functions, there's no concept of instance or class methods. When we evaluate the example, we see the result is similar. New map looks like our modified map in the Ruby example, but the first one, my map, has remained unchanged. Let's just break down a little bit of what's happening within our transform function. So we call this update bang method, and we call it via the map module. We don't call a method on an object because there are no objects, if I don't call update on a hash, instead I'm gonna reference through the map module and use this update bang method. In this case, update bang will raise an exception if the key isn't present in the map. So the update function takes three arguments, a map, a key, and a function, and the third argument is an anonymous function that takes the value at the map key as its argument and passes that value to its own function code. And then here the function code uses the angle bracket string concatenation operator to combine the two values. So let's look back at the Ruby example one more time. We could try to make the Ruby example immutable. Dot dupe would keep the original hash unchanged. We could also try dot freeze, which will do the same thing in this case by raising a runtime error. But both freeze and dupe only produce a shallow copy. So if we were to trivially change our Ruby example, we can see that immutability doesn't hold for nested objects. And quite frankly, neither of these approaches is practical across your code base. I'm not gonna litter dot dupe or dot freeze with every method call I write. And if I'm trying to make Ruby immutable, probably I've sort of started down the wrong path from the get go. So some language specific concepts that probably have already come up and will come up again, just so we're all on the same page. Elixir uses lists, not arrays, maps, not hashes, although they're very similar. There are no objects. Elixir has modules and modules package groups of functions together. The beam is the Elixir, sorry, the Erlang virtual machine, and that's where all Phoenix and Elixir code is executed. We see we have a tuple, which is ordered collection of elements between the curly braces, where the symbol or atom at the front represents the successor fail state of a function call, often. And in general, there's no for loops, no iteration. Elixir favors recursion and higher order functions like map and reduce. So looking at a Rails project and Phoenix project, there are a number of similarities with how they're used. Mix module in Elixir combines the role of bundler and rake. Bundler and now Rails under the Rails 5 world under a single, wrapped in a single module, can generate migrations. There are a number of code generators. You can generate application, controllers, views, et cetera. Unlike Rails, Phoenix requires you to explicitly define your pluralizations. And if we look at project structure, a Phoenix project is reasonably similar to a Rails project. It doesn't look all that different. The underscore build folder contains our compiled project files. The depths folder contains our dependencies, priv static files as well as migrations. And if we look at the web folder, the web folder in a Phoenix project is pretty similar to the app folder in a Rails project. Channels in this case are the Phoenix equivalent of action cable or web sockets. And if you look at Phoenix 1.3, which is in release candidate form, it's gonna introduce a number of changes to the project. And it's way beyond the scope of this talk to go into all of them. But it's important to note, if you knew up a Phoenix 1.3 project, it's gonna look a little bit different than your 1.2 application. So Postgres is the default adapter for a new Phoenix project. And there is support for other adapters present. It's not always up to date with the latest release of Ecto. Personally, I was really surprised to see that there's not one, but two Microsoft SQL adapters. And both the msequel.ecto and amnesia adapters are new, at least on the Ecto repo page since I started working on this presentation. Things are happening. Okay, so Phoenix is an MVC framework and let's kind of step through that a little bit and look at the different pieces of that. Let's look at a controller first. So we have a Rails controller and a Phoenix controller. And there's not a whole lot of difference between these at a glance, but let's look a little bit more closely. A Phoenix controller action requires two arguments. The first is the con, which represents the web request. And in Rails, we get this implicitly via application controller. From the Rails docs, they tell you as much. It comes in invisibly to you as the developer. And that's okay. That's not a bad thing. It's part of the speed and ease of development that Rails offers. But there's a different way of approaching your controller. So as Phoenix requires the con passed in explicitly, maybe we wonder how the con got there. So let's jump back up the stack and look. So this is the endpoint module. And we don't need to get into what's happening here in specifics, but I just wanna sort of call out that with our Phoenix app, we're declaring sort of each plug that we're gonna put in, which a plug represents more or less a transformation. It'll be each transformation that happens to your web request as it comes into your application. We're gonna parse, log, do all those other things that will convert an HTTP request into structs that you can then modify with your application code. Most of the time, you don't need to worry about this, like rack in Rails. But when you do, when you need to look into what's happening, it's nice to know that it's mapped out somewhere and you can review it. This is also a really great place to add your own custom functionality if you need something like a rack, something to do that thing that you need. So plug and rack are rather similar. And actually, if you look, their specifications are really similar. Plug however can be used almost anywhere while rack is wired into place at the beginning of a rack app. If we were gonna do that in sort of rack in Rails, we can do that, but it sort of involves shimming relative to some other piece of functionality. Not necessarily anywhere you wanna use it, but early in the call stack related to something else. Okay, it's back to our controller. Second argument in the controller is a map in this case, which is going to destructure the request parameters in a variable called data. Since we're in an MVC framework, it looks like we're probably developing something restful. We expect there might be a database query here. So let's put that in and see what that would look like. Note with a query, we're not invoking the query through the model, like a find or a find by. Instead, we specify the repo, the actual repo module through the application itself and then specify the model table against which we wanna query in the function arguments. This is gonna be a slightly different. The interface to the repo will be slightly different in Phoenix 1.3. Again, worth noting. So we can change our query to use something other than the primary key and our controller is gonna require that we declare the view template that we're gonna use. There's no implicit assumption based on which view file we're gonna render. And again, that's not a trivial issue in an app like this, but something's been around since Rails 2 to 3 to 4, on its way to 5, where your view folder has 40 sub-folders in it. That's definitely no small amount of cognitive overhead saved. So we're gonna use the plug render function to name the view template we wanna use and assign the result of our query to a variable for use by the template. And because we're explicitly rendering, we can easily switch out the view template we wanna show. So stepping back a little bit, Phoenix isn't an application itself. I think I mentioned this earlier. But it's an important distinction that becomes apparent after you work with Elixir and Phoenix for a while. Phoenix itself is an implementation of an OTP app written in Elixir. The Phoenix layer is more or less a routing layer to the code that you write. With Rails, you're relying on the often implicit promise that your app offers, whether it's rendering a view by naming assumption, routing based on a similar assumption, or exposing instance variables across responsibility boundaries. Rails is there to help, but it makes Rails the centerpiece of what is more ostensibly your business and your application logic. Because of the way you interact with your own code and the Phoenix code in the application by passing data structures to functions instead of sharing Rails or ActiveRecord objects between classes, it's conceptually harder, at least for me, to think of Phoenix as a thing that's doing a lot of the heavy lifting. And I think this can leave your application code more isolated and less prone to getting bound up in the MVC framework layer. So if we go back to our Elixir example, how can we structure this and make it just a little bit more functional? And we can use the pipe operator for that. Piping values, which is passing the value from the left into the function on the right as the first argument, is a more idiomatic way of expressing the flow of data into a function. So we can move our map to the left of the pipe operator, and then it's passed in as the first argument to this function. And in our example, that's a small improvement. The code executes the same, maybe it reads a little bit better. But if we look at another example, for me, this expresses better the way data flows through a module as a series of discrete but related steps. This conceptualizes back better to the HTTP request response cycle and expresses what your application code is doing. Future me appreciates code that's self-evident and doesn't rely on implicit actions and potential side effects. And partially that's because current me forgets what my code does within a few days of committing it to source control. So any web request can be viewed as a function. And for me, this was a big aha moment of writing functional code for the web. The call itself has all the information you need to figure out the state of the world and serve the appropriate response. Web requests are stateless functions. They have to be to work on the worldwide web. And this is just as true in Rails as in Phoenix. There's no reason you can't or shouldn't structure your Rails app in a way that expresses a discrete series of transformations to get you from request to response. I think this is where the structure imposed by your language and your framework can really have an influence on how you write your application code. So back to, we'll step now and look at what's happening in a Phoenix model. Side note, as frameworks go, Phoenix has gotta be one of the harder ones to Google for. Phoenix model does not get you what you think you're gonna get you most of the time. You definitely need to include the elixir modifier on that one. Okay, so as we saw in the controller show function, database queries don't rely on model functions. They rely on the model in order to reference and access the database table name, but the queries are functions called on the Ecto-repo module. So this really limits our models to handling schema and data validation. So if we expand the web model function from the previous slide, we can just see that it wraps the import of a few Ecto modules, including change set and query. You can define a UUID as the primary key. And then we define the schema within the model itself as opposed to a schema file. Set field names, name and a type. We can also add default or null values to our schema here. So Ecto change set was one of the modules we imported. Change sets are how Ecto transforms data structures like maps and lists into more formal structs, which we can then insert or update into the database. And Ecto provides a number of functions to manipulate our change set data. Cast will make a best effort attempt using the field types defined in the schema to coerce the params non-destructively. We can validate our required, ensuring that our params map has keys for all the values that we expect to be in our database on our table. And we can update change with something more, a more invasive coercion. So this is definitely longer and more boilerplate than writing an active record insert. But you are explicitly calling out the validations that you want. It's also less dry. You're adding validations, which probably duplicate the structure that you've imposed on your database. But by validating in the model, you can handle errors and provide error messages back to the user. You can also write a custom validation. So note we're pattern matching via the case statement here on the result of the valid position ID function. Then we can take our custom validation and wire it back into the change set validation pipeline. Within our custom validation, we can add an error message back to the change set, which we'll send back to the request response. So this is more or less the extent of our pretty basic Phoenix model. But because we're also not using the model to query the database, the models naturally get skinnier as they're primarily concerned with ensuring data validity. There's definitely a whole lot more to say about Ecto and working with the persistence layer, but that would actually be an entire talk on its own. Somebody gave one here last year, Ecto and Active Record. So that's something, a reference there, if anybody wants that. So back to a controller, which will handle the result of interacting with our model layer. So the model validations we were just looking at come off a change set function. We use our change set example to perform an insert action. So the create function is the corresponding controller action. So let's simplify our example a little bit. Note again, we're gonna pattern match off the result of our repo insert function. The repo insert will return a tuple, the order collection of items between the curly braces. And the okay atom tells us the insert works as expected. So we can continue on with our happy path. When the change set error, when the change set fails whatever validations we've defined, we can return error messages back to the view. We can take those errors, set an HTTP status code, add error and flash warning messages, error and warning flash messages, and put the entire create function back together. We can render a view, which would look like this for a very vanilla Phoenix app. It's a little brief aside. Rich Hickey, the author of closure has a great talk where he discusses the perils of easy, easy versus complexity, and how easy can disguise complexity. And I definitely encourage you guys to watch it. So Rails is easy. It embraces convention over configuration. And it's able to do most of what I want automatically. But the ease of Rails disguises and hides its complexity. Rails is often performing some complex work under the hood. Phoenix on the other hand is less easy. It requires more explicit code and it requires you to think about your application differently. The explicitness of your Phoenix framework application encourages keeping things simple. A model in Phoenix is a good example of this. It really only does data validation. You need to use an entirely different module to query the same table. But this command separation structure can keep the overall structure of your application simpler and easier to reason about. And in general, this design pattern is entirely possible within Rails, but it's often the way a language or a framework is used that reflects the design choices we make when using it. So we move from a controller to a model back to a controller and let's look at the view. Phoenix views are pretty simple, similar to Rails views. They work pretty similarly. They're functions. They're invoked by the Phoenix render function, usually from the controller. And you need to explicitly define the view module, template, and the variables for the function, for the view function. This is a basic application template, not particularly interesting on its own. Really, the part we care about is where the template wires up the render function. This is similar to a yield block in a Rails template. Define our view module. You can add a decorator function to that module. Then we can render our show template. This template uses EEX code, which basically is ERV code, similar enough that it shouldn't look all that different. Then we can take the title function that we've defined and add it back into our template, which would look like this. I did have Bojack on there before DH's keynote yesterday, so odd little coincidence. Okay, anyway, so that was a pretty long walk through a basic web request. But I really wanted to emphasize the similarities between Phoenix and Rails. Getting started writing Elixir code in Phoenix shouldn't be too daunting of a challenge, and it should feel familiar enough for you to dip your toe in to try it out. But Phoenix isn't Rails. They're similar, but they're not the same. And it's when you start getting into the differences, that you start to appreciate the strengths of Elixir and the Phoenix framework. We didn't really even touch testing, but take it for me, your tests run fast, there's little to no stubbing, there's no mocking or doubling. Tests are easy to write and usually don't require a lot of elaborate setup. I feel like I'm not doing the Phoenix side justice if I don't mention microsecond response times, which everybody loves, but we wrote an app that basically does one thing and has one database record, so that's not really a meaningful measurement. As you grow your application, you can add queues and background workers just by adding code. You don't need any additional infrastructure. A queue and a queue worker exists as Erlang beam virtual machine processes which get started and supervised by your application itself. Your application has the capability for failure handling built in. Within the OTP framework, it provides a supervisory tree and that supervisory tree sort of monitors everything that's running. It monitors your application, monitors the queue workers that you've set up, other pieces of the connection to your database. Within that supervisory tree, your app can and is designed to crash. It just gets restarted and keeps right on going while barely missing a beat, but Elixir and Phoenix are too immature you might say. And while it is true that Elixir and Phoenix are relatively new, a Phoenix framework application is an OTP app and this is a pretty well understood, well defined operational pattern. Phoenix is Elixir code and Elixir transpiles Erlang byte code that runs on the beam virtual machine. This code base has been matured and battle tested since the 80s which makes it older than Java. The beam like the JVM is the party piece of the Erlang ecosystem. It's super lightweight, fast, fault tolerant, scalable. And because it's so lightweight, you can grow your application with less need for additional infrastructure. There are cases where a library that you need or some piece of functionality may not exist in Elixir yet. Although that's becoming less and less true every day as more packages are written for the Elixir ecosystem. However, in many cases, similar libraries possibly do exist in Erlang and Elixir is fully interoperable with Erlang. So it's no problem to import the libraries that you might need. Should I use Phoenix? Part of me wants to say categorically yes and you should experiment with Phoenix. I mean, it depends though. If the subtext of this question is can I do this XYZ thing that I need to do, then the answer is probably yes. But you may need to write your own code or your own package for it. But I've often found that when I get really tied to the how of an implementation, I may not be thinking broadly enough about the what and the why. And there may be a different path towards the same end. However, if the should I use Phoenix question is more like is Phoenix right for my company or maybe more accurately is my company right for Phoenix? Then that answer depends a lot more on your company and your risk profile for new technology. If you want to be an advocate, I think it helps if you can develop some core competency within your organization, whether that's a group of developers who attend meetups, write some toy apps for an informal learning session like a lunch and learn. I think the key is to grow interest and a competency in the framework first. Learning curve, however, is not as steep as you might think. The similarity between Rails and Phoenix really works to your advantage here. So let me leave you with a quote from the great Jim Jarmusch film, Ghost Dog Way of the Samurai. So the second half, it's the same for anything that's called a way. If one understands things in this manner, you should be able to hear about all ways and be more and more in accord with his own. I hope I've helped you to understand the Phoenix framework a bit better and maybe consider using it for an upcoming project. With that said, I'm not advocating abandoning Rails. Phoenix is new and shiny and that has its own appeal, but it's a different tool in our toolbox that may be more suited to some problems than others. As Rails or Elixir programmers, I believe there's a lot of benefit in exploring different technologies, not just because they provide a different way of doing things, but because different methods can reflect back on how you've done things and reveal new aspects of what you've been doing all along.