Skip to content

Instantly share code, notes, and snippets.

@schneems
Last active August 29, 2015 14:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schneems/a153a1d05ae215ca3a63 to your computer and use it in GitHub Desktop.
Save schneems/a153a1d05ae215ca3a63 to your computer and use it in GitHub Desktop.

Proposal: Annotated Config

Problem Statement

Rails promotes "convention over configuration". The convention provides a good baseline to start, but almost all apps must deviate in some large or small fashion, especially when it comes to config/environments/*.rb. This is even true between different environments. By default development and production have different configuration.

Many developers become accustomed to "what works" in one environment and do not try their code in a production environment until they actually deploy to production. This leads to a very confusing series of debugging steps, starting with "I don't understand...it works locally", and ending in "what is different". This is a problem, it leaves developers with a broken production application, a demoralizing, and unclear problem to solve as well as no easy way to actually see "what is different".

To make matters worse, different configuration can do different things between Rails versions see (https://github.com/rails/rails/commits/master/guides/source/configuring.md). One of the largest examples would be the asset pipeline config.assets.digest = true option. At one point this option resulted in assets with MD5 "fingerprint" and without, later the behavior was changed to only produce assets with "fingerprint".

Keeping track of these configuration behaviors and changes is difficult. That difficulty leads to failed deploy, excess time spent debugging, and developer pain.

Proposed Solution

Instead of relying on developers to cross reference a rails guide (that may or may not apply to their version), or to simply "try it out". I would like a way to see in one place exactly what all of my config is doing and what it is set to in a given environment.

$ RAILS_ENV=production rake config

- `config.assets.digest`

  Enables the use of MD5 fingerprints in asset names.
  Current Value: true

- `config.assets.precompile`

# ...

We could use the same functionality to programatically produce some or all of the configuring guide.

This still doesn't solve the "thinks are broken" problem, but it will be useful for debugging why. Quite a few support questions come in to Heroku are and guessing what their current config value is set to. This comes up when someone deploys to "staging" but is looking at their config in production.rb (happens all the time, and we recommend against it https://devcenter.heroku.com/articles/deploying-to-a-custom-rails-environment).

It also happens because people don't read the documentation on what exactly a config statement is doing instead guessing at the functionality based on the name and any comments around it. Even if they do read the docs sometimes they mistakenly believe the last part is true for their app

Set to false in development mode, true in production.

The task could take an argument of the exact config you are looking at

$ RAILS_ENV=production rake config assets.digest

- `config.assets.digest`

  Enables the use of MD5 fingerprints in asset names.
  Current Value: true
  Set at: config/initializers/asset_stuff.rb:25

We could even tell them where the value is being set. Sometimes this can be hard to find if the config is coming from a gem.

It would be nice if this was aggressive about matching so that rake config assets would return all asset configuration.

Implementation

We would need some kind of annotated configuration object. We could introduce a new method

set_config :perform_caching do |config|
  config.annotate = "Configures whether the application should perform caching or not."
  config.default  = ->(env) { env.production? true : false }
end

By default the accessor methods are created and nothing more. If the task is called we can set a flag in ConfigMethods that tells all methods to register their annotations. Then when the method writer is called, we can store the caller so we know where it was set.

Feedback

This is a spitball idea, i'm interested in basically any feedback regarding the problem, proposed solution, or implementation.

Please give feedback in person, over email, or chat. Github does not send out notifications on gist coments

@thesowah
Copy link

Great idea! I agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment