How members have set up their Elixir dev environment

basics:

  • OS: FreeBSD everywhere desktop laptop & servers
  • FreeBSD jails and zfs snapshots for lighweight testing and deployment
  • dtrace on FreeBSD and recon for debugging and tracing BEAM apps live. I’ve never needed pry & friends.
  • haproxy on my computer to redirect http requests and databases to whatever jail is actually running at that time
  • urxvt terminals appropriately titled for the task at hand, i3 for window manager, fish shell
  • devel/zeal: an offline docs browsing tool
  • git-cola: super graphical git commit tool for unix

BEAM

  • lang/elixir, rebar, rebar3, mix, hex all installed from FreeBSD packages
  • installed lang/erlang, erlang-runtime19, erlang-runtime20, lang-erlang-runtime21 all from packages (yes you can have them concurrently installed)
  • I switch between the erlang versions with a simple set PATH /usr/local/lib/erlang20/bin $PATH where needed. I cannot tell you how nice this is.
  • the packages are upgraded regularly usually 1-2 days after official OTP and elixir releases so you’re always patched without stress

editor

  • neovim with vim-plug, alchemist, vim-mix, vim-mix-format, network, a bunch of std tpope vim plugins (commentary, fugitive, sensible, projectionist), all the vim-erlang/* plugins, rainbow, vim-better-whitespace, ctrlp
  • I also have intellij-ultimate which I use for “larger” project management - moving stuff between files, its nice to use the mouse with tabs and many files sometimes

comms

  • irc via irccloud.com or hexchat
  • slack & hipchat for work-related stuff

workflow

I typically have a couple of windows open - a running elixir app on the left pane in a while loop, so I just need to ctrl-C to have it restart if needed.

mix clean; while mix format
  iex --name hive --cookie yum -S mix
  clear
end

and in that one I use ConCache to “copy” interesting data from the running program into the iex repl to play with. I often have network ports and pids in the values, so having real ones to play with is critical. this looks like this:

iex(hive@wintermute.skunkwerks.at)4> conn = ConCache.get(:webhook_cache, :req) 
%Plug.Conn{
  adapter: {Plug.Adapters.Cowboy.Conn,
   {:http_req, #Port<0.1471292>, :ranch_tcp, :keepalive, #PID<0.18751.0>,
    "POST", :"HTTP/1.1", ...

iex(hive@wintermute.skunkwerks.at)6> conn |> Plug.Conn.get_req_header("x-real-ip")

You can then do all the nice stuff right there in the repl! When I have the rough form of the desired function or module working, I switch over to vim in the right side window, write tests around my desired behaviour, throw in the code from IEx into a module, and profit.

The conn above is captured using a little Plug I shift around inside the app while I’m fiddling:

defmodule CapnHook.Debug do
  @moduledoc """
  Pretty Print the conn with nice colours
  """

  @highlighting [number: :yellow, atom: :cyan, string: :green, nil: :magenta, boolean: :magenta]

  use Plug.Builder

  def call(conn, _opts) do
    ConCache.put(:webhook_cache, :conn, conn)
    IO.inspect(conn, label: __MODULE__, syntax_colors: @highlighting, width: 0)
    conn
  end
end

In my final pane, I run a syslog tail on top, and a small window on bottom with mix test --trace --no-deps-check --stale until it’s all good.

then switch over to git-cola, order some smaller commits, do the distillery dance to produce a release, and I have a small script that turns that tarball into a deployable FreeBSD package.

If anybody’s interested in more details, message me, and I’ll spin this into an actual blog post.

16 Likes