Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Figuring Out Configuration

Figuring Out Configuration

a primer on `config` in elixir applications,

Daniel Mackey

May 29, 2019
Tweet

More Decks by Daniel Mackey

Other Decks in Technology

Transcript

  1. Hey, I'm Mackey! — Engineering Manager @ Cars.com — Developer

    @ ❤ — @heymackey or @danielmackey on interwebs chicago elixir // 05.29.19 2
  2. 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
  3. Origin Story — a recovering Rubyist. — a jaded Javascripter.

    — an elementary Elixirist. chicago elixir // 05.29.19 4
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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: "<replace with password>" # config/dev.secret.exs config :playground, SecretClub, password: "h0d0r" chicago elixir // 05.29.19 18
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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