sb logoToday I Learned

Avoid nesting configuration

Often, I will see configuration nested under some thematic element, rather than the configuration’s intended usage. Let’s imagine that I want to mock out my mailer during tests, so I’ll store the actual mailer as a module attribute at compile time, and fallback to the actual module.

# config/test.exs
import Config

config :my_blog, :content_management, [mailer: MockMailModule, minimum_words: 200]

While this configuration makes sense thematically, the usage is going to be very different.

def MyBlog.Marketing do
  @mailer Application.compile_env(:my_blog, :content_management)[:mailer] || MailModule

  def send_marketing_email do
    @mailer.email("hi")
  end
end

This is fine, and it definitely works, but it would be simpler if we didn’t nest our configuration, and modeled it around the usage pattern.

# config/test.exs
import Config

config :my_blog, :content_management_mailer, MockMailModule
config :my_blog, :content_management_minimum_words, 200

Now we can leverage the default argument of compile_env/3

def MyBlog.Marketing do
  @mailer Application.compile_env(:my_blog, :content_management_mailer, MailModule)

  def send_marketing_email do
    @mailer.email("hi")
  end
end