Chapter 1. Ride the Phoenix

This chapter covers

  • What Phoenix is and its benefits
  • The power of the Elixir programming language
  • The differences between object-oriented and functional programming
  • Some potential drawbacks to using Phoenix and Elixir

Phoenix is a web framework built on top of the Elixir programming language. Every day, Phoenix and Elixir applications

  • Provide real-time communications between thousands and thousands of users on limited hardware
  • Process data on highly distributed systems
  • Respond gracefully to errors by having supervisors restart workers when they crash
  • Provide simple or complex websites to users all over the world

In this chapter, you’ll be introduced to the Elixir programming language and the Phoenix web framework. We’ll take a look at the main advantages and disadvantages a language like Elixir and a framework like Phoenix provide. By the end of the chapter, you’ll have a good overview of these technologies and why they exist, and you’ll be ready to jump into learning the details and creating your own web applications.

1.1. What is Phoenix?

Phoenix is a web framework that aids in the creation and maintenance of dynamic websites, but it doesn’t attempt to copy the big players in this space, such as Ruby on Rails. Phoenix is built on top of the Elixir programming language, which is a functional language. Although Phoenix has best practices and suggestions for structuring and maintaining your applications, it isn’t as dogmatic about these suggestions as Ruby on Rails and other frameworks are, giving you the flexibility to write your applications as you see fit.

As shown in figure 1.1, the Phoenix framework is written in the Elixir language, which in turn runs on the Erlang VM (virtual machine).

Figure 1.1. Phoenix is written in Elixir, which compiles down to run on the Erlang VM.

Over the years, some high-profile companies have embraced Phoenix and Elixir. They have done so in varying degrees—some started with just API servers, some used them for internal tooling, and some have gone all-in and moved everything over. Companies such as Pinterest, Slack, Discord, Lonely Planet, Bleacher Report, Undead Labs (the company behind the hit video game State of Decay), and Opendoor are on this ever-growing list. The ability to dip a toe into the world of Phoenix or fully dive in is one of the great things about Elixir and Phoenix. They can handle any size of project you throw at them, and do so very cost-effectively.

Phoenix goes beyond many web frameworks as well. For example, Phoenix has the concept of channels built in. Channels allow for “soft-realtime” features to be easily added to applications. We’ll cover the topic of channels in depth in later chapters, but they allow you to have chat applications, instantly push updates to thousands of simultaneous users, and update pages without a full-page refresh. These kinds of features can be difficult to add in other languages and frameworks, but it borders on trivial for Phoenix applications—you’ll learn how to add them to your applications in a single chapter.

1.2. Elixir and Phoenix vs. the alternatives

Let’s look at a few of the exciting things Phoenix offers. The following sections certainly don’t provide an exhaustive list of Phoenix’s benefits, but they will give you an idea of some areas in which the framework shines. We’ll cover a number of these in more detail in this book.

1.2.1. Real-time communication

What can you do with real-time communication? Well, any time you want to push information to many users simultaneously, you’ll need some solution for that. For example, in a chat application where users can send chat messages to thousands of other users and receive them in return, you need to keep each client up to date when another user submits a new message. A more complex example would be an auction site that wants to provide users visiting the auction item’s page with up-to-the-second information regarding the state of the bids. You might have a workplace collaboration site where users are sharing files and even working on the same file simultaneously. Or perhaps you want to build a real-time multiplayer game server, and you need to ensure that all players have the same information at the same time. Real-time communication is necessary in many different situations and beneficial in many more.

Figure 1.2 illustrates a typical “pull” request, in which the user has to request new information from the server.

Figure 1.2. Traditional “pull” refreshes require the user to initiate the request and the server to return the entire web page.

Figure 1.3 illustrates a simple situation in which bandwidth can be saved and the user experience improved by pushing data to the user instead of requiring the user to pull the data from the server.

Figure 1.3. A “push” request originates from the server and pushes new information (typically only changed information) to the user, greatly reducing the payload and speeding up page rendering.

As the world moves more and more toward mobile communication, the real-time aspects of Phoenix can be hugely beneficial.

1.2.2. Efficient, small processes

Elixir can spawn and efficiently handle hundreds of thousands of processes without blinking an eye (we’ll go into a bit more detail later in this chapter). When creating channels for real-time communication, Phoenix spawns each channel in its own process, so that no single process can damage or take down any of the others—they’re isolated.

Using these processes and channels, Phoenix can handle hundreds of thousands of connections on a single server. Kudos to you if your web application ever has hundreds of thousands of simultaneous users wanting to communicate in real time, but that gives you an idea of the power of Phoenix and channels running within processes.

You’ll add channels in the application you’ll build over the course of this book.

1.2.3. Background computation

There will be times during development when you’ll want to execute a long-running computation or process but won’t want to keep the user from interacting with your application. For example, a user of an e-commerce site may want to purchase a product that’s first customized and then downloaded. When the user finalizes the purchase, you don’t want to require them to wait on that page until the personalization process is complete. Instead, you’d like them to continue to browse your store or set up their profile. This is a simple scenario in which background computation can play a role. Figure 1.4 shows how a similar asynchronous request may progress.

Figure 1.4. Background processes can do complex work without holding up the main responses to the user.

If your application needs to do more than a small amount of computation in the background (normally asynchronously), it’s a perfect fit for a framework built on top of Elixir, like Phoenix. It’s trivial to kick off asynchronous background processes with Elixir.

1.2.4. Minimal hardware requirements, low-cost scaling

If you look at any hosting provider’s offerings, you’ll notice that adding more CPU power or cores usually costs less than adding more RAM. This fits perfectly with the way Elixir works. Elixir automatically utilizes all the CPU cores available to it and uses a relatively small amount of RAM in order to run. Compare this to a web framework and language like Ruby on Rails, which is RAM-hungry.

Other web frameworks built on different programming languages can scale, but if you’re looking for a low-cost way to scale quickly, Elixir and Phoenix might be a good choice. Pinterest explains in a blog post that they moved one of their systems from Java to Elixir (http://mng.bz/6jMA):

So, we like Elixir and have seen some pretty big wins with it. The system that manages rate limits for both the Pinterest API and Ads API is built in Elixir. Its 50 percent response time is around 500 microseconds with a 90 percent response time of 800 microseconds. Yes, microseconds.

We’ve also seen an improvement in code clarity. We’re converting our notifications system from Java to Elixir. The Java version used an Actor system and weighed in at around 10,000 lines of code. The new Elixir system has shrunk this to around 1000 lines. The Elixir based system is also faster and more consistent than the Java one and runs on half the number of servers.

1.2.5. It’s not all roses

Although the Elixir language and the Phoenix framework are awesome and are usually what I reach for when starting new projects, they’re not always the best choice for the job. Some areas in which Elixir doesn’t do as good a job as the alternatives include the following:

  • Time to productivity— If you’re already productive in a different web framework using a different programming language, it may be hard to justify the cost of getting up to speed in something new like Elixir. If you’re just getting started in development, one consideration is how long it will take you to become productive in your new chosen language. Some people I’ve spoken to believe it’s harder to learn functional programming (FP) than object-oriented programming (OOP), and others swear it’s the other way around—functional programming just clicks with them. Either way, I believe that Elixir and Phoenix offer enough reasons for you to take the plunge and learn the language, regardless of your past experience levels.
  • Numbers— Elixir isn’t a number-crunching powerhouse. It will never match the pure computational speed of something lower-level like C or C++. I’d even go so far as to say that if you’re primarily looking to crunch large numbers, even Python would be a better choice. Elixir can do it and do it well, but it will rarely win in a head-to-head competition in this area.
  • Community— Although the community behind Elixir, Phoenix, and Erlang is very helpful and enthusiastic, it’s not as large or established as the communities for Ruby, Python, Java, or even PHP. Those languages have a deeper and longer history in the web application world, and it might be easier to find help with your project in one of those communities. But more and more meetups, conferences, blogs, and jobs are arriving all the time for Elixir, and I believe the future holds great things for the Elixir community.
  • Packages— In keeping with Elixir’s smaller and younger community, the number of open source packages available for use in your project is smaller. As I write this, there are currently just under 8,000 packages available on hex.pm, the package manager source for Elixir. Contrast that with rubygems.org, which has over 9,800 packages, and PyPI (the Python Package Index), which has over 165,000. But although it may be harder to find something that exactly matches what you had in another programming language, more packages are being built all the time. This also means there’s space for you to create a helpful new package and help grow the community.
  • Deploying— I originally considered including a chapter on deploying applications in this book, but this is an area that’s still in need of a single, “best” solution. Deploying an Elixir application (including ones that use the Phoenix web framework) is pretty tricky and involves multiple steps—steps that are still not clearly defined and that don’t have mature tools to help with the process. However, many smart people are putting tremendous resources toward a solution, and I believe one is just around the corner (it may be available by the time this book is released).

Phoenix provides a lot of things that help you add normally complex features to your web applications, but it won’t be the foundation of your application. It may be strange to read that in a book specifically about Phoenix, but the truth is that Phoenix derives its powers from the amazing Elixir programming language.

1.3. The power of Elixir

Phoenix is a framework built on top of Elixir—so what is Elixir? Here’s a quote from the Elixir homepage (http://elixir-lang.org):

Elixir is a dynamic, functional language designed for building scalable and maintainable applications.

Elixir leverages the Erlang VM, known for running low-latency, distributed and fault-tolerant systems, while also being successfully used in web development and the embedded software domain.

Erlang has a long and interesting history. It was developed at Ericsson (the telecommunications company) and first appeared in the world around 1986. Ericsson used it internally for years to handle telecommunication jobs (such as powering telephone exchanges) around the world, but it became open source in 1998. Erlang is known to be a good fit for applications that must be fault-tolerant, distributable, highly available, and performant. One of the exciting things about Elixir is that it’s built on top of this 30-year old VM, and it utilizes those decades of knowledge and experience and marries them with nice syntax and metaprogramming support (among other things).

Let’s look at some more things that make Elixir an exciting language to work with.

1.3.1. Scalability

One of the amazing things about Elixir is its scalability. Elixir has the idea of processes running on your machine. These aren’t processes as you may have thought of them in the past—they aren’t threads. Elixir processes are extremely lightweight (the default initial size is 233 words or 0.5 KB) and are independent of all other running processes. You’ll build a Phoenix application through the course of this book, and you shouldn’t find it surprising that a nontrivial number of concurrent processes will be running on your machine to allow the application to run. These processes are fast, are independent of each other, have unshared memory, and can easily send messages to and receive them from other processes on distributed nodes (different machines potentially in different parts of the world).

1.3.2. Supervision trees

Elixir applications (including Phoenix apps) have supervisors and workers. Supervisors monitor the workers and ensure that if they go down for one reason or another, they’re started right back up. This provides an amazing backbone of fault-tolerance without much work on your part. You can configure how you’d like your supervisors to handle their workers if something does happen to them, including shutting down and restarting any sibling workers. Beyond that, supervisors can supervise other supervisors! The supervision tree can get pretty large and complex, but this complexity doesn’t necessarily mean your application will be harder to comprehend.

Figure 1.5 shows a scenario in which a supervisor is in charge of rooms for scheduling purposes. Among those rooms, there’s another supervisor that’s in charge of a subset of rooms. The top-level supervisor can certainly supervise the supervisor.

Figure 1.5. Supervisors and workers

Figure 1.6 illustrates a real-life application developed by a friend of mine. Each dot is either a supervisor, a process being supervised, or both, which should give you an idea of how many processes can be spawned during the running of a moderately complex application. This application is constantly running in the background to find scheduling conflicts for an organization’s physical assets, such as rooms, buildings, projectors, chairs, and the like. Each supervisor handles a group of rooms. When a request comes in, each supervisor gets a request to ask each of the rooms it supervises whether there are any scheduling conflicts. If any of the child processes has any trouble and crashes, the supervisor notices and starts it right back up.

Figure 1.6. Your application can spawn thousands of workers, each one isolated from the others.

The benefits of these processes and supervisors are many. One, in particular, is that creating distributed systems is much easier than is possible in other languages. You can deploy your code to multiple servers in multiple locations around the world (or in the same room) and have them communicate with each other. Need more power? You can bring up another server node, and your previous nodes can communicate with the new node with minimal configuration, passing off some of the required work as they see fit.

1.3.3. Erlang VM

The preceding features are available to us because the backbone of Elixir is Erlang. Erlang has been around for decades now, silently and dependently providing services to many of the things you use on a daily basis. Erlang was created with the telecommunications industry in mind, and what does a telecommunication service require? High fault-tolerance, distributability, live-updating of software—things that a modern-day web application should also be able to rely on. Elixir runs on top of the Erlang VM, which is rock-solid and has been for decades. You can even run Erlang functions and use Erlang modules directly in your Elixir applications! This book won’t go into the details of Erlang and its VM, but there are plenty of resources available that cover Erlang.

Erlang and WhatsApp

There’s a great story about Erlang and the popular messaging app WhatsApp, which was acquired by Facebook for $19 billion in 2014. When it was acquired, it had 450 million users sending over 70 million Erlang messages per second. If WhatsApp had been built on a programming language other than Erlang, it likely would have had a huge engineering staff. But because the application was written in Erlang, and Erlang provides so many benefits for real-time messaging applications, the engineering team at the time of acquisition consisted of only 35 people. Your application may not ever have 450 million users sending 70 million messages per second, but why not utilize technology that would allow you to easily do so if required?

1.3.4. Macro and metaprogramming support

Although Elixir runs on the Erlang VM, it is itself written in Elixir. How is that possible? This is another of the great things about the Elixir language—macros. Elixir is extensible via built-in support for macros, which allow anyone to define their own language features. You can build your own little language or DSL within Elixir itself. As figure 1.7 illustrates, 90% of the Elixir codebase is itself Elixir—the rest is made up of Erlang and various shell files.

Figure 1.7. Breakdown of language types in Elixir’s source code (as of December 2018)

1.3.5. OTP

One feature of Elixir that can’t go unmentioned is its ability to utilize OTP. OTP stands for Open Telecom Platform, but that name isn’t very relevant anymore, so you’ll almost always just see OTP.

OTP is a set of functions, modules, and standards that make using things such as supervisors and workers—and the fault-tolerance that goes along with them—possible. OTP includes concepts such as servers, concurrency, distributed computation, load balancing, and worker pools, to name just a few. It’s been lightheartedly said that any complex problem you’re attempting to solve has likely already been solved in OTP.

If half of Erlang’s greatness comes from its concurrency and distribution and the other half comes from its error handling capabilities, then the OTP framework is the third half of it.

Frederic Trottier-Hebert, “What is OTP?” in the tutorial Learn You Some Erlang for Great Good!

With all that greatness backing Phoenix, what if you don’t know Elixir? That’s OK. Elixir is a relative newcomer in the world of programming languages. Chapter 2 will take you through the basics of the Elixir language, and you can refer to appendix B for some extra resources you can check out. As a teaser, the next section is a very brief tour of what Elixir looks like and how it functions.

1.4. Functional vs. object-oriented programming

First and foremost, Elixir is a functional programming language. A few of the biggest bullet points of the benefits of FP include

  • Data is treated as immutable (unchangeable).
  • When given the same input, a function will always return the same output.
  • The code produces no side effects.

As a result, applications developed in functional languages are relatively easy to reason about, predict, and test.

Ruby, Python, Java, and C# are all OO languages and are widely used in web application development. In recent releases, even historically procedural languages like PHP and Perl have been gaining OO features. And although the number of developers productively using these languages remains high, there seems to be a recent shift away from the notion that OOP is the best way forward, and toward more FP languages (such as Elixir, Haskell, Lisp, Clojure, and so on). Even though most OOP languages can be applied in a functional way, having a language that’s strictly functional from the beginning has its advantages.

1.4.1. Overview of functional programming

Functional programming is all about data transformation. Mutable (changeable) data and changing state are avoided (and in some cases are impossible). A function that’s called with the same parameters any number of times will return the same answer every time. In purely functional code, no data outside of that function will be considered when the return value is computed. One of the results of this is that the return values of functions need to be captured in order to be used again—there’s no object involved that encapsulates its own state.

Let’s suppose you want to do some calculations regarding a race car and keep track of things like what kind of tires it has, its speed, its acceleration, and so on. You could group that information into an Elixir module that would not only define the structure of the data but also be a central place to hold all the race car functions.

Let’s take a look at what a race car module might look like in Elixir. Don’t worry too much about the syntax—we’ll cover that later. The following listing should give you an idea of the code syntax and structure.

Listing 1.1. An example RaceCar module in Elixir
defmodule RaceCar do
  defstruct [:tires, :power, :acceleration, :speed]        1

  def accelerate(%RaceCar{speed: speed, acceleration: acceleration} =
   racecar) do
    Map.put(racecar, :speed, speed + acceleration)         2
  end
end

ferrari_tires = [                                          3
  %Tire{location: :front_right, kind: :racing},            3
  %Tire{location: :front_left, kind: :racing},             3
  %Tire{location: :back_right, kind: :racing},             3
  %Tire{location: :back_left, kind: :racing}               3
]                                                          3
ferrari = %RaceCar{tires: ferrari_tires,                   4
                   power: %Engine{model: "FR223"},
                   acceleration: 60,
                   speed: 0}
ferrari.speed
# => 0
RaceCar.accelerate(ferrari)                                5
# => 60
ferrari.speed                                              6
# => 0
new_ferrari = RaceCar.accelerate(ferrari)                  7
new_ferrari.speed
# => 60
ferrari.speed
# => 0

  • 1 Defines a struct and the attributes it will have
  • 2 Map.put doesn’t modify the original variable’s data but instead returns a new representation with the updated data.
  • 3 Tires are defined as four Tire structs. The Tire definition isn’t in this listing.
  • 4 Creates the RaceCar
  • 5 Tells the RaceCar module to accelerate the ferrari
  • 6 The underlying data doesn’t change.
  • 7 You need to capture the output if you want to use the data after acceleration.

Look carefully—the ferrari variable isn’t changed when you pass it to the RaceCar.accelerate/1 function.[1] You could run that line 1,000 times and you’d get the same return value every time: an updated structure of the ferrari with a new speed. But remember, the original ferrari doesn’t change in memory. You have to capture that return value in order to use it later.

1

The RaceCar.accelerate/1 syntax means the accelerate function inside the RaceCar module that has argument arity (the number of function arguments) of 1.

What this kind of programming offers is the elimination of side effects. You can run your function at any time and be confident that it will always return the same value for the same input—regardless of the time of day, global state, what order the functions were called in, and so on.

Eliminating side effects, i.e., changes in state that do not depend on the function inputs, can make it much easier to understand and predict the behavior of a program, which is one of the key motivations for the development of functional programming.

Wikipedia “Functional programming”

In simple terms, OOP involves objects holding onto their own state (data) and providing methods that allow the outside world to access, modify, or even delete that data. In contrast, Elixir modules don’t store state (data) on their own—they simply provide functions that operate on the data passed to them and return the resulting data to the caller.

Figure 1.8 illustrates how objects handle data in OOP, and figure 1.9 illustrates how FP paradigms handle data. In the latter case, the data does not belong to the module.

Figure 1.8. Object-oriented programming generally involves an object that keeps track of its own data (state). Methods are used to manipulate that internal state and retrieve it for other uses.

Figure 1.9. Functional programming generally involves a module that contains functions that act together for a purpose. The module holds no data (state) but returns the result of the function acting on data the caller gives it.

In the world of OOP, an object’s internal data or state can be mutated by many things during an operation. Because of the often dynamic nature of OO languages, a third-party package could hook into your codebase and modify your data without you even knowing. In contrast, when working with Phoenix, the data flows in a single line from the user making the request to the requested page being displayed. And for each step the data takes, you specify how that data is passed along. The side effects are therefore minimal (and usually are eliminated entirely).

1.5. Keep reading

This chapter has provided a brief overview of what Phoenix and Elixir are and some of the benefits they provide to developers. Hopefully, it has also piqued your interest in the language and framework. In the next chapter, you’ll be introduced to the Elixir language, in case you’re not already familiar with it. Then, starting in chapter 3, we’ll dive into Phoenix. By the end of the book, you’ll have written a very basic auction site (like eBay) with real-time bidding. Let’s get going!

Summary

  • Phoenix has many advantages over similar web frameworks, and much of that is because it’s built with Elixir.
  • Elixir is built on top of Erlang, which is accompanied by decades of work, knowledge, and best practices.
  • Functional languages provide a different style of thinking than object-oriented languages. Although there are benefits to each, a purely functional style is gaining favor among web developers.
  • Some companies have utilized Elixir and Phoenix in just a few key areas of their applications, and others have embraced them in every aspect of their business.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.70.203