RailsConf 2017

Rails to Phoenix: How Elixir can level-you-up in Rails

Rails to Phoenix: How Elixir can level-you-up in Rails

by Christian Koch

In the talk titled "Rails to Phoenix: How Elixir can level-you-up in Rails" at RailsConf 2017, Christian Koch introduces the Phoenix framework, highlighting its advantages for Ruby on Rails developers. Koch emphasizes that Elixir, the language behind Phoenix, allows for substantial improvements in web app development, particularly for those familiar with Rails. As he outlines the goals of his presentation, he aims to thoroughly familiarize his audience with Phoenix while discussing its underlying technologies, including Elixir, OTP, and Erlang.

Key points discussed include:
- Framework Similarities: Koch points out that both Rails and Phoenix are designed for productivity, leveraging convention over configuration. Although they share many aesthetic and structural qualities, they diverge significantly in their programming paradigms, with Phoenix being functional and Elixir-based.
- Functionality of Elixir: Elixir's functional programming model emphasizes immutability, which means operations return new data structures instead of modifying existing ones. This approach leads to fewer side effects and more predictable code behavior.
- Advantages of Phoenix: Koch cites that Phoenix applications, compiled for the Erlang VM, exhibit high performance, enabling them to handle immense traffic with far fewer resources than a traditional Rails stack (citing an example from Bleacher Report, which reduced server counts drastically).
- Controller and Model Comparisons: Further exploring differences, Koch compares Rails controllers and models to their Phoenix counterparts, elaborating on how data is handled in function calls rather than objects, which simplifies the model-making process and enforces better data validation practices.
- Development Patterns: The talk underlines the explicit nature of coding in Phoenix, where developers must define their data flows and request handling without relying on the implicit behaviors often found in Rails. This requires a shift in thinking but ultimately allows for cleaner architecture.
- Operational Stability: Koch explains how the underlying OTP framework in Erlang contributes to fault tolerance and system stability, allowing for seamless recovery from errors.

Koch concludes his presentation by encouraging Rails developers to explore Phoenix as an alternative tool, emphasizing that while Phoenix is not a replacement for Rails, it provides distinct advantages in specific scenarios. He reinforces the idea that embracing different technologies can enrich a developer's skill set, ultimately leading to better problem-solving capabilities in software development.

00:00:11.840 Hello, everyone. Welcome to my talk. Today, I want to discuss the Phoenix framework.
00:00:17.609 My name is Christian Koch, and I'm from NCSA in Chicago. I have a few goals for today's talk.
00:00:26.119 First, I want to familiarize you with the Phoenix framework generally. Additionally, I hope to connect our discussion to Elixir, OTP, and Erlang.
00:00:32.730 I will explain some of these concepts shortly.
00:00:40.440 So, what this talk is not? Unfortunately, there will be no Phoenix puns.
00:00:46.170 I'm sorry about that, but I recognize that you are a sharp RailsConf crowd. I certainly don't need to pander to you with pictures of my cats, as that would be an insult.
00:00:51.539 Now, why not talk about Rails?
00:01:04.049 That's a reasonable question to ask at RailsConf. I didn't come here to tell you to abandon your Rails apps. I'm not an evangelist.
00:01:09.750 Rails is great, and I enjoy working with it. I know it very well. It's fast to deliver functionality and quick to develop.
00:01:16.799 However, I don’t particularly enjoy trying to scale my Rails apps.
00:01:23.040 Scaling usually requires more than just spinning up additional servers and often involves new technologies in the stack.
00:01:28.650 For example, Redis, Sidekiq, or perhaps Elasticsearch.
00:01:36.689 Let's consider one alternative: the Phoenix framework.
00:01:42.390 There are many similarities to Rails; they share many of the same motivations.
00:01:49.049 Chris McCord, who was a Rails programmer, created the Phoenix framework.
00:01:54.479 Both frameworks are designed to be productive.
00:01:59.610 They emphasize convention over configuration and both are server-side MVC frameworks.
00:02:04.619 However, there are important differences.
00:02:10.560 Phoenix is written in Elixir, a functional programming language.
00:02:15.900 A Phoenix app is compiled and it isn't just an app; it's an implementation of an OTP application written in Elixir.
00:02:21.630 Today, I may use Elixir and Phoenix interchangeably because the Phoenix framework is fundamentally constructed in Elixir.
00:02:27.300 By design, programming with Phoenix is programming with Elixir.
00:02:39.500 So, what exactly is the Phoenix framework?
00:02:45.870 It is a web framework written in Elixir, which is a functional language developed from Erlang.
00:02:51.720 Let’s look at what each of these components entails.
00:02:56.790 Functional programming provides data immutability.
00:03:01.950 This means actions taken on data structures always return a new data structure while leaving the original unchanged.
00:03:07.260 In functional programming, there are no objects or classes; rather, you pass data, like hashes and arrays.
00:03:15.090 Functions are first-class citizens in Elixir.
00:03:21.390 Erlang is a programming language used to build scalable, soft real-time systems.
00:03:26.790 It has requirements for high availability and was originally developed by Ericsson to support telecom infrastructure.
00:03:33.930 The fault tolerance required for seamless failover makes Erlang ideal for web applications.
00:03:39.390 With a syntax that bears some similarity to Prolog, Erlang is used by several production companies, including WhatsApp.
00:03:46.650 The OTP, or Open Telecom Platform, is not quite a full-fledged framework.
00:03:53.070 Instead, it is a collection of Erlang libraries and design choices that support the development of distributed applications.
00:04:00.390 These applications are highly available, supervised, and resistant to failure.
00:04:07.140 Elixir, designed by José Valim, is a dynamic functional language.
00:04:13.370 Its syntax is somewhat similar to Ruby.
00:04:19.019 Elixir offers the possibility of building distributed, scalable, maintainable applications with low overhead.
00:04:24.060 Let's talk about why Phoenix is important.
00:04:29.820 Phoenix is written in Elixir and designed to run on the Erlang virtual machine, making it functional and immutable.
00:04:36.450 It is asynchronous, scalable, lightweight, and fast. A Phoenix app is compiled for runtime stability.
00:04:42.360 Its design is well-suited to today's web environment, where multi-core processors run multiple processes.
00:04:53.610 Numerous companies are running Phoenix in production.
00:04:59.370 For example, Bleacher Report claims they handled eight times more traffic after transitioning from Rails to Phoenix.
00:05:05.580 They reduced their server count from 150 to just five. While this sounds a bit exaggerated, it illustrates a key point.
00:05:12.320 Now, let's look at a practical example.
00:05:16.170 In this Ruby example, we define a class and a method to modify a hash by adding a value.
00:05:22.320 When evaluated, both the original and new hashes share the same value since mutating directly can lead to shared references.
00:05:30.060 Let's now translate this example into Elixir.
00:05:35.580 Instead of a class, we define a module and create a function within it.
00:05:41.490 Since a module is just a collection of functions, there's no concept of instance or class methods.
00:05:47.669 When evaluated, the result appears similar: the new map is modified while the original remains unchanged.
00:05:55.620 Let's break down the workings of the transformation function.
00:06:03.480 We call the 'update!' method via the map module, as there are no objects to call methods on directly.
00:06:10.800 The 'update!' function requires three arguments: the map, the key, and an anonymous function.
00:06:15.810 The function processes the value of the map key as an argument.
00:06:21.330 In Elixir, the immutability of data structures allows us to avoid unintentional side-effects.
00:06:28.020 If we revisit the Ruby example, we could use 'dup' to create a copy, keeping the original hash unchanged.
00:06:33.210 However, this only results in shallow copies and doesn't work with nested objects.
00:06:39.750 Language-specific concepts will arise.
00:06:45.120 In Elixir, we use lists instead of arrays, and maps in place of hashes.
00:06:51.900 Instead of objects, Elixir has modules, which are groups of functions.
00:06:57.300 The BEAM is the Erlang virtual machine where all Phoenix and Elixir code executes.
00:07:04.590 Tuples are ordered collections of elements defined between curly braces.
00:07:11.180 In Elixir, there isn't a for loop; instead, it emphasizes recursion and higher-order functions.
00:07:16.500 Examining a Rails project alongside a Phoenix project, we can identify several similarities.
00:07:22.169 In Elixir, the 'mix' module combines the roles of bundler and rake.
00:07:29.610 In a Phoenix project, we can generate migrations and controllers, views, and more.
00:07:36.750 Unlike Rails, Phoenix requires explicit pluralization definitions.
00:07:43.920 The structure of a Phoenix project is reasonably similar to that of a Rails project.
00:07:49.680 The '_build' folder contains compiled project files, while the 'deps' folder contains necessary dependencies.
00:07:55.350 In a Phoenix project, the 'web' folder closely resembles the 'app' folder in Rails.
00:08:01.280 Channels in Phoenix serve as the equivalent of Action Cable or WebSockets.
00:08:07.510 With the upcoming Phoenix 1.3 release, several changes are set to be introduced.
00:08:14.750 Therefore, if you start a new Phoenix 1.3 project, it will differ from the 1.2 version.
00:08:20.350 Postgres is the default adapter for new Phoenix projects.
00:08:25.750 While there is support for other adapters, they may not always align with the latest release of Ecto.
00:08:31.300 Interestingly, there are not one but two Microsoft SQL adapters available.
00:08:37.070 Both the MSSQL Ecto and Amnesia adapters are relatively new.
00:08:43.200 Now, let’s discuss the MVC structure in Phoenix.
00:08:48.540 To begin, let's look at the controller.
00:08:55.500 For example, a Rails controller and a Phoenix controller demonstrate minimal differences.
00:09:00.880 In Phoenix, a controller action requires two arguments: the connection and the parameters.
00:09:06.220 In Rails, the connection is often implicit, derived from the application controller.
00:09:12.000 This aspect is part of the speed and ease of development that Rails provides.
00:09:18.950 In contrast, Phoenix requires a more explicit handling of the connection.
00:09:27.700 If you're wondering how the connection comes into play, we can examine the endpoint module.
00:09:35.480 In a Phoenix app, you declare each plug to represent a transformation.
00:09:41.570 Each transformation in your web request processes as it enters the application.
00:09:48.500 In many cases, you don’t need to worry about this like you do in Rails, but it's good to know it's laid out.
00:09:55.170 This location is also a great place to add custom functionality if necessary.
00:10:01.920 So, plugs and racks are similar; however, plugs can be anywhere.
00:10:06.570 Essentially, they are similar in how they affect web requests.
00:10:12.270 Now, the second argument in the controller action is a map.
00:10:19.470 It structures request parameters into a variable called 'data'.
00:10:25.050 Since we are working in an MVC framework, we likely expect there to be a database query.
00:10:31.110 Interestingly, when we perform a query, we don't invoke it on the model as in Rails.
00:10:37.080 Instead, we specify the Repo module, designating the model table for our query.
00:10:43.710 This format will change slightly in Phoenix 1.3.
00:10:49.310 Our controller must declare the view template to be used.
00:10:56.570 There's no implicit assumption on which view file gets rendered.
00:11:02.470 This clarity is not trivial in an application, especially larger ones.
00:11:09.080 We can easily switch out the desired view template because it is defined explicitly.
00:11:15.420 Phoenix as a framework itself acts as an interface.
00:11:22.110 It is essential to denote that Phoenix is an implementation of an OTP app.
00:11:29.350 With Rails, you tend to rely on implicit promises your app offers.
00:11:36.860 This can include assumptions about view rendering or using shared instance variables.
00:11:43.270 In contrast, Phoenix operates differently.
00:11:49.970 Interacting with your own code involves passing data structures to functions instead of sharing objects.
00:11:56.780 This conceptual shift can isolate your application code, reducing complexity.
00:12:03.520 Now, let's explore how we can structure this to be more functional.
00:12:10.020 We can use the pipe operator, which helps express the flow of values through functions.
00:12:16.670 This way presents data more clearly as it moves through a series of transformations.
00:12:23.200 Functionally, this fits well into the HTTP request-response cycle.
00:12:29.960 Any web request can be viewed as a function, capturing all necessary information for processing.
00:12:35.430 Statelessness is crucial for the Web, and both Rails and Phoenix share this characteristic.
00:12:41.450 There's no reason you can't structure your Rails app in a manner expressing a series of discrete transformations.
00:12:49.610 The design structure imposed by your language and framework influences how you write application code.
00:12:55.490 Looking now at the Phoenix model, it's often harder to search for information.
00:13:01.920 Typically, typing Phoenix model won't yield the relevant search results.
00:13:08.280 As we've seen, database queries don’t rely on model functions but on the Repo module.
00:13:15.460 This means models in Phoenix primarily manage schema and data validation.
00:13:21.530 Expanding the 'Web' model function imports some Ecto modules.
00:13:28.390 This structure defines the schema directly within the model instead of a separate schema file.
00:13:34.900 You set field names, data types, and any default or null values as needed.
00:13:41.320 Change sets are how Ecto transforms data structures like maps and lists into formal structures.
00:13:48.160 Ecto provides functions to manipulate change set data.
00:13:54.330 For example, the 'cast' function will attempt to coerce parameters non-destructively.
00:14:01.190 You can validate required fields to ensure they exist in the parameters.
00:14:07.400 Updating a change set applies more invasive coercion to the data.
00:14:13.050 While the manual boilerplate is lengthy, you explicitly declare validations.
00:14:20.660 While this might feel less DRY, validations in the model can help manage error responses.
00:14:27.160 Moreover, you can write custom validations with error messages attached.
00:14:33.030 Continuing with our basic Phoenix model, they tend to get skinnier as they revolve around data validity.
00:14:39.950 There's much more to explore regarding Ecto and the persistence layer.
00:14:46.840 Next, let’s return to the controller and see how it interacts with the model.
00:14:53.970 The change set function performs insert actions.
00:14:59.640 The 'create' function in the controller corresponds directly to this action.
00:15:06.010 Pattern matching is used on the result of the Repo insert function.
00:15:12.640 The return will typically be a tuple indicating success or failure.
00:15:18.240 The 'ok' atom confirms the expected result, allowing us to proceed down the happy path.
00:15:25.570 If the change set fails due to validation issues, we respond with error messages.
00:15:32.030 This includes setting HTTP status codes and error or warning messages.
00:15:39.880 Bringing everything back together, we render a view for the vanilla Phoenix app.
00:15:46.340 Rich Hickey, the author of Closure, discusses the complexity found in simplicity.
00:15:52.340 Rails embraces convention over configuration.
00:15:58.320 This makes it easier to work with, but it hides complexity.
00:16:04.060 In contrast, Phoenix is less straightforward, requiring more explicitness.
00:16:09.610 This encourages simplicity, showcasing how models in Phoenix perform data validation.
00:16:16.590 While separate modules are needed for database queries, this architecture fosters a clear separation.
00:16:23.040 Despite this could also be achievable within Rails, the core framework's use may dictate the design.
00:16:29.400 Transitioning back to the controller, we'll now examine Phoenix views.
00:16:37.620 They're simple and invoke functions via the render instruction from the controller.
00:16:44.220 You need to explicitly define the view module template and the corresponding variables.
00:16:50.470 The basic application template might not be intriguing on its own.
00:16:57.260 The crucial part is where the template integrates the render function.
00:17:03.610 This resembles a yield block within a Rails template.
00:17:09.930 To define our view module, we can add a decorator function, rendering our show template.
00:17:17.140 The template utilizes EEx code, which looks similar to ERB.
00:17:24.020 We can incorporate the previously defined title function back into our template.
00:17:30.000 After a lengthy examination of a basic web request, I wanted to highlight the similarities between Phoenix and Rails.
00:17:37.290 Getting started with Elixir code and Phoenix shouldn't be overly daunting.
00:17:43.700 It should feel familiar enough for you to comfortably explore.
00:17:50.640 However, Phoenix is not Rails.
00:17:55.590 While they're similar, they differ significantly.
00:18:02.740 It’s through these differences that we start to appreciate the strengths of Elixir.
00:18:09.260 We didn't delve into testing, but trust me: tests run quickly.
00:18:16.410 There’s minimal need for mocking or stubbing, and tests are generally easy to write.
00:18:23.080 Response times in Phoenix apps are microseconds, which is impressive.
00:18:30.160 While we've developed a simplistic app with one database record, which may not provide meaningful metrics,
00:18:38.520 You can effectively add queues and background workers simply by incorporating code.
00:18:47.040 Queues exist within the Erlang VM processes, beginning and managed by your application.
00:18:53.310 Built-in failure handling is a notable feature of the OTP framework, which provides a Supervisory tree.
00:19:00.000 This structure monitors running processes and your database connections.
00:19:06.830 Your application is designed to crash, being restarted, minimizing disruption.
00:19:13.250 Elixir and Phoenix may seem immature compared to more established technologies.
00:19:18.950 However, a Phoenix application is effectively an OTP application.
00:19:26.000 This is a well-defined operational paradigm, with Phoenix and Elixir powering the application.
00:19:33.000 This code has been battle-tested since the 1980s, making it older than Java.
00:19:40.020 The BEAM, similar to the JVM, is powerful within the Erlang ecosystem.
00:19:45.820 It is lightweight, fast, fault-tolerant, and highly scalable.
00:19:53.370 Due to its lightweight nature, growing your application requires relatively less infrastructure.
00:20:00.210 While some libraries might not be available yet, the elixir ecosystem is growing rapidly.
00:20:07.090 However, many similar libraries do already exist.
00:20:13.290 Elixir is fully interoperable with Erlang, simplifying library imports.
00:20:20.500 Should you use Phoenix? Yes! I encourage experimentation with it.
00:20:27.130 However, the answer depends on your specific needs.
00:20:34.490 If your query is about completing specific tasks, the answer is likely yes.
00:20:41.570 You might just need to create your own solutions or packages.
00:20:48.480 However, if it’s about whether Phoenix is right for your company, that relies heavily on your context.
00:20:54.630 Building core competency within your organization can support advocacy for Phoenix.
00:21:01.210 Encouraging your team to build an interest and skillset can help.
00:21:07.870 Interestingly, the learning curve isn't as steep as you might expect.
00:21:15.090 The similarities between Rails and Phoenix provide a distinct advantage.
00:21:24.040 Let me leave you with a quote from Jim Jarmusch's film 'Ghost Dog: The Way of the Samurai'.
00:21:33.430 "The second half is the same for anything called a way. If one understands things this way, it should be easier to be in accord with their own path."
00:21:39.680 I hope I've helped you understand the Phoenix framework better.
00:21:46.140 Consider using it in an upcoming project, but I'm not advocating abandoning Rails.
00:21:52.140 Phoenix is new and shiny, enticing in its own way, yet it remains a different tool in our toolbox.
00:22:01.500 It suits specific problems better than Rails does.
00:22:08.370 As Rails or Elixir programmers, exploring different technologies can provide great benefits.
00:22:15.340 These explorations not only convey different methods of doing things but may also challenge previous perspectives.
00:22:22.750 Thank you for your attention.