Slide 1

Slide 1 text

figuring out configuration a primer on config in elixir applications. chicago elixir // 05.29.19 1

Slide 2

Slide 2 text

Hey, I'm Mackey! — Engineering Manager @ Cars.com — Developer @ ❤ — @heymackey or @danielmackey on interwebs chicago elixir // 05.29.19 2

Slide 3

Slide 3 text

spoiler alert — we're hiring — some games of thrones material — but don't worry, I won't ruin anything like D&D chicago elixir // 05.29.19 3

Slide 4

Slide 4 text

Origin Story — a recovering Rubyist. — a jaded Javascripter. — an elementary Elixirist. chicago elixir // 05.29.19 4

Slide 5

Slide 5 text

You know nothing, Jon Snow. chicago elixir // 05.29.19 5

Slide 6

Slide 6 text

how does configuration work? chicago elixir // 05.29.19 6

Slide 7

Slide 7 text

first, the basics chicago elixir // 05.29.19 7

Slide 8

Slide 8 text

use Mix.Config chicago elixir // 05.29.19 8

Slide 9

Slide 9 text

import Config, soon chicago elixir // 05.29.19 9

Slide 10

Slide 10 text

use Mix.Config, for now chicago elixir // 05.29.19 10

Slide 11

Slide 11 text

Basic example # config/config.exs use Mix.Config config :playground, :foo, "pitied" # iex -S mix Application.get_env(:playground, :foo) "pitied" chicago elixir // 05.29.19 11

Slide 12

Slide 12 text

config is easy as cake # config/config.exs use Mix.Config config :playground, foo: "pitied" import_config "#{Mix.env()}.exs"` # config/dev.exs use Mix.Config config :playground, foo: "fooed", bar: "barred" # iex -S mix iex(1)> Application.get_env(:playground, :foo) "fooed" iex(2)> Application.get_env(:playground, :bar) "barred" chicago elixir // 05.29.19 12

Slide 13

Slide 13 text

Module example # config/config.exs use Mix.Config config :playground, SwingSet, kind: "aluminum" config :playground, SwingSet.Swing, seat: "bucket", chains: "rope" # iex -S mix Application.get_env(:playground, SwingSet) [kind: "aluminum"] Application.get_env(:playground, SwingSet.Swing) [seat: "bucket", chain: "rope"] chicago elixir // 05.29.19 13

Slide 14

Slide 14 text

Why does that work? In Elixir, module names are atoms. iex(1)> is_atom SwingSet true iex(2)> to_string SwingSet "Elixir.SwingSet" iex(3)> :"Elixir.SwingSet" === SwingSet true chicago elixir // 05.29.19 14

Slide 15

Slide 15 text

beyond the basics chicago elixir // 05.29.19 15

Slide 16

Slide 16 text

Dealing with sensitive values — Passwords, API Keys, Client Secrets, etc. — Don't want in source control. — Might change based on environment. chicago elixir // 05.29.19 16

Slide 17

Slide 17 text

locally // source .gitignore has config/*.secret.exs ignored by default[^*]. Write a mix alias to copy config/dev.secret.example.exs to config/dev.secret.exs chicago elixir // 05.29.19 17

Slide 18

Slide 18 text

locally // source - example # config/dev.exs if File.exists?("#{Path.dirname(__ENV__.file())}/dev.secret.exs") do import_config "dev.secret.exs" end # config/dev.secret.example.exs config :playground, SecretClub, password: "" # config/dev.secret.exs config :playground, SecretClub, password: "h0d0r" chicago elixir // 05.29.19 18

Slide 19

Slide 19 text

remotely // environment fetch from ENV variables on the "machine" # bad idea config :playground, :surface, System.get_env("SURFACE_TYPE") chicago elixir // 05.29.19 19

Slide 20

Slide 20 text

compile-time vs. run-time Mix.Config is evaluated whenever mix starts. This can be during mix phx.server or mix release. In the case of mix release, it is evaluated when (and where) the release is built. Dynamic values configured via System.get_env will get evaluated then and there. chicago elixir // 05.29.19 20

Slide 21

Slide 21 text

remotely // environment fetch from ENV variables on the "machine" # good idea config :playground, :surface, "${SURFACE_TYPE}" # + REPLACE_OS_VARS=true exported on your runtime machine chicago elixir // 05.29.19 21

Slide 22

Slide 22 text

battle scars chicago elixir // 05.29.19 22

Slide 23

Slide 23 text

gotcha #1 Sometimes you might want to optimize evaluating by setting module attributes and reading from them. defmodule SwingSet do @config Application.get_env(:playground, SwingSet) # ... def kind() do @config[:kind] end end This means @config gets set at compile time, even if you are trying to do run-time eval. chicago elixir // 05.29.19 23

Slide 24

Slide 24 text

gotcha #1 options Read the configuration at runtime. defmodule SwingSet do def kind() do Application.get_env(:playground, SwingSet)[:foo] end end chicago elixir // 05.29.19 24

Slide 25

Slide 25 text

gotcha #2 Handling when $ENV is not set properly # Bugs Are Coming config :playground, :osha safety: "${MUST_BE_HERE}" || raise ("MUST_BE_HERE wasn't") eye_protection: "${EYE_PROTECTION}" || "sunglasses" if $MUST_BE_HERE is not set, evaluates to "" , and we'll never get raise(...) chicago elixir // 05.29.19 25

Slide 26

Slide 26 text

gotcha #2 options — write a config helper to wrap the value with a raise if empty string — wait for Elixir 1.9 where mix release gets config/ releases.exs, config providers, etc. chicago elixir // 05.29.19 26

Slide 27

Slide 27 text

Elixir 1.9 changes — Elixir 1.9 will ship with Config built in. — use Mix.Config so! deprecated, long live import Config — mix new will no longer generate a config/config.exs — Umbrella applications will no longer generate a apps/config/*.exs chicago elixir // 05.29.19 27

Slide 28

Slide 28 text

a small detour... chicago elixir // 05.29.19 28

Slide 29

Slide 29 text

config under an umbrella All sub applications share the same config, just like the same dependencies. Causes problems when different apps in the umbrella that need different config. Some libraries will allow you to get around that (ueberauth's otp_app: :playground). chicago elixir // 05.29.19 29

Slide 30

Slide 30 text

Elixir 1.9 Config System.get_env/2 (2nd arg optional) Returns the value of the given environment variable. If value isn't set, returns nil or optional second arg as default. System.fetch_env/1 Returns an {:ok, value} if value present, or :error if not System.fetch_env!/1 Returns the value if present, or raises ArgumentError chicago elixir // 05.29.19 30

Slide 31

Slide 31 text

the end? chicago elixir // 05.29.19 31

Slide 32

Slide 32 text

Thanks! Find me at - GitHub: @heymackey - Twitter: @danielmackey - Web: danielmackey.com P.S. - We're hiring @ Cars.com - See me @ ElixirConf in Denver! chicago elixir // 05.29.19 32