Introduction to Elixir

Why Elixir

Now we create almost all our applications or websites using Ruby. Ruby has many advantages like elegant syntax, fast development, a lot of free libraries (gems) that can be used to solve almost any task. With this, it has some disadvantages: it is considered one of the slowest languages, it consumes a lot of system resources, it has bad concurrency implementation.

Elixir on the other hand is free of this disadvantages: it is fast, it is light, and it has amazing concurrency. What about syntax? If you are used to Ruby – Elixir will look very familiar. Also Elixir with its frameworks promise to have compared development speed to Ruby development speed.

What is Elixir

 José ValimElixir was created by José Valim, ex-member of the Rails core team. José took Erlang language, mixed it with Ruby syntax and gets this ambitious Elixir.

Main differences between Ruby and Elixir

  • Elixir is a compiled language. Its code compiled to Erlang byte code and runs by Erlang VM. This means that Elixir has inherited all the Erlang advantages.
    What is Erlang?
    As we know from Erlang home page – Erlang is a programming language used to build massively scalable soft real-time systems with requirements on high availability. Some of its uses are in telecoms, banking, e-commerce, computer telephony and instant messaging. Erlang’s runtime system has built-in support for concurrency, distribution and fault tolerance.
  • Elixir is a functional language. It has no classes, only modules with module functions.

    Ruby example (OOP style)

    class Concat
      attr_reader :value
    
      def initialize(value)
        @value = value
      end
    
      def join(another_value)
        value + another_value
      end
    end
    
    irb> Concat.new("Yo").join("!!!")
    irb> => "Yo!!!"
    

    Elixir example

    defmodule Concat do
      def join(value, another_value) do
        value <> another_value
      end
    end
    
    iex> Concat.join("Yo", "!!!")
    iex> "Yo!!!"
    

  • Elixir inherited Erlangs pattern matching

    Ruby `=` operator is called assign operator

    irb> a = 1
     => 1 
    irb> a, b = 2, 3
     => [2, 3] 
    irb> 1 = 1
    => SyntaxError...
    


    Elixir `=` operator is called pattern match operator. And you can assign values or assign-when-match with it.

    iex> a = 1
    1
    iex> [a, b] = [1, 2]
    [1, 2]
    iex> 1 = 1
    1
    iex> {:ok, message} = {:ok, "Success"}
    {:ok, "Success"}
    iex> message
    "Success"
    iex> {:ok, message} = {:error, "Error"}
    ** (MatchError) ...
    

  • Elixir has functions rarity (Erlang feature). Any Elixir module can have multiple functions with the same name. Which one will be used is determined with the help of pattern matching

    defmodule SampleResult do
      import IO, [:puts]
      def show do
        puts "Nothing to show"
      end
    
      def show(:ok, message) do
        puts("Success: " <> message)
      end
    
      def show(:error, message) do
        puts("Error: " <> message)
      end
    
      def show(a,b,c) when a == 1 do
        puts("Are you crazy?")
      end
    end
    
    

    iex> SampleResult.__info__(:functions)  
    [show: 0, show: 2, show: 3]
    
    iex> SampleResult.show
    Nothing to show
    
    iex> SampleResult.show :ok, "Yay!!!"
    Success: Yay!!!
    
    iex> SampleResult.show :error, "OOPS!!!"
    Error: OOPS!!!
    
    iex> SampleResult.show 1, 2, 3
    Are you crazy?
    
    iex> SampleResult.show 0, 1, 2
    ** (FunctionClauseError) no function clause matching in SampleResult.show/3
    
    

Who uses Elixir Erlang in production?

There are no well-known brands who use Elixir in production. But Erlang is widely used by leading companies. And Elixir becomes Erlang when compiled.

  • Erlang is used by WhatsApp and Facebook bought it for $ 19 billion.
  • Amazon uses Erlang to implement SimpleDB.
  • Yahoo! uses it in its social bookmarking service, Delicious, which has more than 5 million users and 150 million bookmarked URLs.
  • Erlang is also used by one of the most popular game – League of Legends

What is Phoenix

“It is productive web framework that does not compromise speed and maintainability.”

Phoenix is an MVC framework build on Elixir. And It has a lot in common with Rails.

  • It has dependency system like in Rails.

    Rails

    
    # https://rubygems.org/
    bundle install
    


    Phoenix

    
    # https://hex.pm/
    mix deps.get
    

  • It has `mix` tasks manager.

    Rails

    rails new blog
    rake db:create
    rake db:migrate
    rails g migration AddUserIdToPosts
    rails server
    


    Phoenix

    mix phoenix.new pxblog
    mix ecto.create
    mix ecto.migrate
    mix ecto.gen.migration add_user_id_to_posts
    mix phoenix.server
    

  • It has scaffold generators.

    Rails

    rails g scaffold Post title:string body:string
    


    Phoenix

    mix phoenix.gen.html Post posts title:string body:string
    

  • It has tests.

    Rails

    rails test
    


    Phoenix

    mix test
    

  • For connection to database it uses Ecto instead of ActiveRecord.

    Rails

    migrations, validations, queries DSL


    Phoenix

    migrations, validations, queries DSL

Performance comparison between Rails and Phoenix

I’ve created simple Rails and Phoenix apps on my local PC, ran servers in production mode, and compared the performance using Apache Benchmark.

And I’m looking forward that everyone who is reading this will repeat my experiment 🙂

The performance was tested on a 2-Core CPU 2800MHz with 10000 requests done by 100 users.


Rails


export RAILS_ENV=production
export DATABASE_URL=postgresql://postgres:postgres@localhost/umbrella_rails
export POOL_SIZE=20
export SECRET_KEY_BASE=secret

rails new umbrella -d postgresql && cd umbrella

# Modify database params in config/database.yml:
production:
  adapter: postgresql
  url: <%= ENV['DATABASE_URL'] %>
  pool: <%= ENV['POOL_SIZE'] %>

# Generate zombies resource
rails g scaffold Zombie name

# Add some records in db/seeds.rb:
Zombie.create!(name: "Dick")
Zombie.create!(name: "Nick")
Zombie.create!(name: "Rick")

# Create database
rake db:create
rake db:migrate
rake db:seed

# Precomple assets
rake assets:precompile

# Change logs level to 'error' in config/environments/production.rb
config :logger, level: :error

# Replace config/puma.rb with
threads 10, 10
port 3000
environment 'production'
workers 2
preload_app!
on_worker_boot { ActiveRecord::Base.establish_connection }

# Run server
rails s


Phoenix


export MIX_ENV=prod
export DATABASE_URL=postgresql://postgres:postgres@localhost/umbrella_phoenix
export POOL_SIZE=20
export PORT=4000

mix phoenix.new umbrella && cd umbrella

# Modify your database params in config/prod.secret.exs
config :umbrella, Umbrella.Repo,
  adapter: Ecto.Adapters.Postgres,
  url: System.get_env("DATABASE_URL"),
  pool_size: String.to_integer(System.get_env("POOL_SIZE"))

# Generate zombies resource
mix phoenix.gen.html Zombie zombies name

# Phoenix don't change routes during scaffolding, so we should add this in web/router.ex:
resources "/zombies", ZombieController

# Compile Phoenix
mix compile

# Create database
mix ecto.create
mix ecto.migrate

# Precompile assets
mix phoenix.digest

# Seed some records in priv/repo/seeds.exs:
alias Umbrella.{Repo, Zombie}
Repo.insert!(%Zombie{name: "Dick"})
Repo.insert!(%Zombie{name: "Nick"})
Repo.insert!(%Zombie{name: "Rick"})

# Run this seeds
mix run priv/repo/seeds.exs

# Change logs level to 'error' in config/prod.exs
config :logger, level: :error

# Start server
mix phoenix.server

Comparison Results

Introduction to Elixir Comparison Results | Shakuro

at_exit

Some statistics (end of 2016):

  • Hex package manager now includes 3.5K packages.
  • Ruby community has 127K gems
  • Latest Phoenix version 1.2.1 was downloaded ~ 2k times per day
  • Latest Rails version 5.0.1 was downloaded ~ 7k times per day

Each programming language should be selected based on your business requirements.  If you choose Ruby, you choose stable and fast development, but possible performance leak. If you chose Elixir, you choose good performance, but not so fast development because of too small community (as of yet).

Anyway, I definitely recommend everyone to play with Elixir and decide whether you can use it in a real application production.

Thanks a lot to authors of: