Posts tagged #elixir

Open your text editor with the migration file when you run mix ecto.gen.migration

There is a neat little trick which I found while browsing Ecto’s code Adding the following line to your ~/.bashrc will open up your new migration file with the text editor of your choice

ECTO_EDITOR="code" # put the name of your editor here
export ECTO_EDITOR

Now, when you run mix ecto.gen.migration, it will open up your editor and you can modify your migration.

I actually use neovim to edit my code. However, it doesn’t open up from erlang. I tried running :os.cmd 'nvim /tmp/a' but it fails with an error about stdin not being found.

Annotating variables with underscore variables to make code more readable

We should always strive to make our code as readable as possible. Underscore variables aid is in making our code more readable by annotating literal values with meanings.

Look at the following variations

without any underscore variable annotation

Tentacat.Contents.find(@owner, @repo, "", client)

While reading the code, it is difficult to know what the third parameter is. In most these cases, I navigate to the actual function definition and read the variable name.

with underscore annotations

Here is an improved version of the same code with and underscore variable annotation. It makes it crystal clear that the third argument is a path.

Tentacat.Contents.find(@owner, @repo, _path = "", client)

What are the techniques you use in your code to make it more readable?

Treat your elixir warnings as errors in your non dev environments

One of the bittersweet things about Go is its relentlessness with warnings. You cannot compile your Go code which has warnings in it. This is great for the long term health of the project. However, it is not so pleasant while writing the code. Elixir takes an opposite approach to this where even errors which should break your build are treated as warnings. One such instance are Behaviours. If you have a module which implements a behaviour and does not implement a non optional callback, all elixir does is emit a warning! It should really throw an error and stop the compilation. However, all hope is not lost! You can use an elixir compiler flag to treat warnings as errors. All you need to do is add the following to your mix.exs:


  def project do
    [app: :awesome_possum,
     #...
     # treat warnings as errors in non dev environments
     elixirc_options: [warnings_as_errors: Mix.env != :dev],
     #...]
  end

You can even hard code it to true and it will always treat warnings as errors. However, non dev is the sweet spot for me, as I may be testing incomplete code with warnings in dev.

You can also pass these options to via the cli like so:


# using elixirc
elixirc --warnings-as-errors awesome_possum.ex
# using mix
mix compile --warnings-as-errors

Using mnesia with distillery

If you are using mnesia with distillery. You may run into an error which likes below:

09:46:26.974 [info]  Application dynamic_store exited: DS.Application.start(:normal, []) returned an error: shutdown: failed to start child: DB
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function :mnesia.create_schema/1 is undefined (module :mnesia is not available)
            :mnesia.create_schema([:"dynamic_store@127.0.0.1"])

This is because distillery doesn’t export mnesia by default. You need to tell distillery to export :mnesia by adding it to the extra_applications option in your mix application.

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger, :mnesia],
      mod: {DS.Application, []}
    ]
  end

When not to use apply for dynamically calling functions in Elixir

Elixir has a nice apply function which allows you to call any module’s function with a list of arguments normally called the mfa. However, I see apply being used in places where it shouldn’t be. Let us take the below example.

defmodule WorkerBehaviour do
  @callback perform(job :: Job.t)
end

defmodule EmailWorker do
  @behaviour WorkerBehaviour
  def perform(job) do
  # ...
  end
end

defmodule ScreenshotWorker do
  @behaviour WorkerBehaviour
  def perform(job) do
  # ...
  end
end

defmodule Processor do
  def process_job(worker_module, job) do
    apply(worker_module, :perform, [job])
  end
end

In this example the Processor.process_job uses the apply function to send the job to the right worker. However, there is a more readable version of this code. Just use the following:

defmodule Processor do
  def process_job(worker_module, job) do
    worker_module.perform(job)
  end
end

Since, in this particular scenario we know beforehand what the name of the function is and the number of arguments is the same for all modules, we can directly invoke the required function on the module using the above syntax. This makes your code more readable overall.

the difference between the for comprehension and Enum.each

Look at the code below and try to guess what happens when you run the following lines of code.

for

for {:resp, f} <- [{:resp, 3}, :b, {:resp, 4}] do
  IO.inspect f
end

Enum.each

Enum.each([{:resp, 3}, :b, {:resp, 4}], fn {:resp, f} ->
  IO.inspect f
end)

The for version chugs along just fine :) which might surprise you. The Enum.map version blows up as expected.

Be careful about using for in your code, especially your tests. I had a small test which was the following lines:

assert length(stats) == 2
for {:resp, stat} <- stats do
  assert stat.meta == %{a: 3}
  assert stat.time_ms in 10..20
end

And this was passing every time even when I changed the assert to the code below.

for {:resp, stat} <- stats do
  assert stat.meta == nil
  assert stat.time_ms in 10..20
end

All because I had an incorrect pattern match. I had {:resp, stat} instead of a { {:resp, _id}, stat }. So, the for was filtering out all the stats and the inner block was not being executed even once.

A simple way to automatically set the semantic version of your Elixir app

There is a neat trick which I bumped into while doing Rails development which I’ve been using to set the semver value of my Elixir Apps.

This works if you use Git for your version control. The basic idea is to use git tags, and the number of commits since the git tag to generate your version number. Elixir allows you to use a version string like below (You can read more about this at https://hexdocs.pm/elixir/Version.html)

[MAJOR].[MINOR].[PATCH]-[pre_release_info]+[build_info]

When I want to bump the major or the minor version, I create a tag with the version information e.g. v1.4 using the command

git tag v1.4 --annotate --message 'Version 1.4'
git push --tags --all

I use the git describe command to get the major, minor and the patch info. A part of the describe output also goes into the build information

git describe
# => v1.4-270-fa78ab71e
# => major.minor-patch-git_commit_id

Putting all of this together, I have the following in my mix config, it also uses the BUILD_NUMBER passed by Jenkins (the build server that we use)

defmodule Dan.Mixfile do
  use Mix.Project

  def project do
    [app: :dan,
     version: app_version(), # call out to another function which generates the version
     # ...
    ]
  end

  # ...

  def app_version do
    # get suffix
    build_number = System.get_env("BUILD_NUMBER")
    suffix = if build_number, do: ".build-#{build_number}", else: build_number # => .build-443

    # get git version
    {git_desc, 0} = System.cmd("git", ~w[describe])
    ["v" <> major_minor, patch, git_commit_id] = git_desc |> String.trim |> String.split("-") # => ["v1.4", "270", "fa78ab71e"]
    "#{major_minor}.#{patch}+ref-#{git_commit_id}#{suffix}" # => 1.4.270+ref-fa78ab71e.build-443
  end

end

Creating such a beautiful version number without showing it anywhere wouldn’t be very useful :) I usually put the version information of the app in a footer and the head inside a meta tag (if it is a phoenix app)

defmodule Dan do

  # cache the app_version during build time
  @app_version Mix.Project.config[:version]
  def app_version, do: @app_version

end

Inside the app.html

<!doctype html>
...
<meta name="version" content="<%= Dan.app_version %>">
...

So, now when something goes wrong I can take a look at the current version of the app by visiting a page and know which precise git commit reproduces the problem. Our QA team too uses this information when filing bug reports.

I also send this version info to my error monitoring and metric services like Rollbar and AppSignal

Hope you find this technique useful :)

How to model an enumerated list of values

When dealing with things like statuses you may need to store and access a fixed set of values. The following is one of way of doing it

defmodule ProductStatus do
  def active, do: :active
  def inactive, do: :inactive
  def cancelled, do: :cancelled
end

If you have a lot of values like these, the above code may become tedious. Metaprogramming to the rescue :)

defmodule ProductStatus do
  @statuses ~w[
    active
    inactive
    cancelled
  ]a

  for event <- @events do
    def unquote(event)(), do: unquote(event)
  end
end

This allows you to use statuses as ProductStatus.active

How to create a Cartesian product of two sets

Elixir has a very rich set of functions to work with collections in the Enum module. The name Enum however, is a bit unfortunate. Enum makes me think of (enumerated data)[https://en.wikipedia.org/wiki/Enumerated_type] more than the enumerable.

Anyway, the other day I needed to compute the Cartesian product between to lists in my elixir app. And, I knew there would be something for that in the Enum module. I went through all the documentation and couldn’t find anything useful. That is when it hit me that comprehensions are best suited for this and this is a piece of cake for comprehensions.

So, without further ado, here is the code to get a Cartesian product in elixir:

a = [1, 2, 3, 4]
b = [1, 2, 3, 4]

cp = for x <- a, y <- b, do: {x, y}
IO.inspect(cp)
# =>
# [{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}]