Skip to content

Clarify Application.get_env by illustrating a use case #7929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 18, 2018

Conversation

caldempsey
Copy link
Contributor

@caldempsey caldempsey commented Jul 18, 2018

The documentation for Application.get_env is not newcomer friendly and can be considered one of the most important and granular functions to understand in the Elixir programming language. In particular, an inexperienced developer will find it difficult to understand from the documentation what is meant by the 'app', 'environment' and 'environment keys' without bouncing between different sources of information. It's then up to the inexperienced developer to make that (frankly quite difficult) connection. When we try to make elicit the concept of scoping in a Mix configuration file, and how that is laden on Application.get_env, and how Application.get_env is then used to acquire the various configurations for our application (which are conceptual leaps we need to make in turn), fundamental to Elixir, we can't do all of that in one place. That is, we can read our 'app' has an 'environment' and those environments have 'keys' (but which app, which environment, and which keys)? We can improve this by providing an example of Application.get_env!

Below I illustrate while this might seem obvious to experienced developers, this is not clear to inexperienced developers given the current standard of documentation. Consider the following example...

# Database configuration

config :my_app, App.RepoTwo,
# Database configuration`

How does our OTP application know the configuration for RepoOne without making a lookup for the module name RepoOne? To answer that question we need to understand how our Mix configuration attains its configuration. We are greeted with...

Returns the value for key in app's environment. If the configuration parameter does not exist, the function returns the default value.

But if the mix.exs file for :my_app includes Ecto within application, so...

def application do
    [
      extra_applications: [:ecto],
    ]
  end

So our 'app' has an 'environment' and those environments have 'keys' (but in practice, which app, which environment, and which keys)? How do I know how Application.get_env is utilized? We can know as experienced developers this is defined by Ecto, but as newcomers assuming no knowledge we are at a disjunction... Do calls to Application.get_env get made by the OTP app we are building, say MyApp, or Ecto itself? An experienced developer can answer calls are being made by Ecto but we are getting the configuration for my_app because Ecto considers the repo part of your application and that's why calls are made there.

But the non-experienced developer finds themselves in a situation where they are trying to understand how our config for config.exs is retrieved by calls to Application.get_env, but have no idea which application is being passed into the parameter (and why). This becomes utterly confusing to people trying to understand error messages raised by applications in related to configuration files, trying to figure out why they need to set the configuration as one atom :my_app than the other :ecto, as people don't have access to all of the information at face value (you have to look in multiple different sources and figure out by yourself how it comes together).

My suggestion (and contribution) is to strengthen understanding to newcomers by means of illustration, by explaining how we can Application.get_env, but explain it so people can understand how the flow of calls could work in a meaningful and accessible way. I feel this is a much-needed feature which will greatly clarify the usage of Application.get_env whether it's via Mix, via an implementing application, iex, or otherwise!

@fertapric
Copy link
Member

fertapric commented Jul 18, 2018

@mmacheerpuppy What do you think about the section "The application environment" in the documentation of the Application module?

If you think that section covers all the details of the application environment, could be enough to include a reference in Application.get_env/3? Something like:

For further details on the application environment, please check the section "The application environment"

If not, I would improve that section :)

@caldempsey
Copy link
Contributor Author

caldempsey commented Jul 18, 2018

@fertapric So, the problem is it talking about it from the perspective of the application resource file. I feel that's a lot to take in and too low level for someone who just wants to fundamentally learn about Application.get_env/2, in particular, and how its used within the various and many applications that reference it (which is super common).

The key env of an application resource file has a list of tuples that map
atoms to terms and its contents are known as the application environment.

I feel that this change is better suited as an example in Application.get_envs for the reason that it abstracts away the detail of application resource files, and directly fulfills the responsibility of providing a walk-through of a situation why we would use Application.get_envs, in particular, in our application. I should make clear the point here is finding the right level of granularity and abstraction for people who just code Elixir, not make things superfluously complex. I feel the level of abstraction is right for people who just want to code in Elixir, and not worry about the details of the application environment.

Providing too much detail, and then not practical use cases or examples serves only to meaningfully reduce the accessibility of our documentation to newcomers.

I would agree a reference could also be suited, or an 'Examples' section perhaps under ## The application environment, but (a) even if I did list it there under an 'Example' it follows that, (b) what I have written provides only an example for a use case of Application.get_env - so suited therein.

@josevalim
Copy link
Member

Thanks @mmacheerpuppy! I have updated the formatting and added a note for library developers. Please let me know what you think.

@josevalim josevalim changed the title Clarify Application.get_env by illustrating a use case. Clarify Application.get_env by illustrating a use case Jul 18, 2018
@caldempsey
Copy link
Contributor Author

caldempsey commented Jul 18, 2018

@josevalim Looks great! You've definitely done a great job at professionally condensing all of the information I wrote, I agree with the detail you did remove (using Enum.reduce doesn't need to be there), and yes a very important note! Have a star ⭐️.

I'll continue to work on bodying out our documentation with more examples like this in different pull requests.

Copy link
Member

@whatyouhide whatyouhide left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with very minor changes, like removing some trailing whitespace and turning localhost into "localhost".

@josevalim josevalim merged commit ff364ff into elixir-lang:master Jul 18, 2018
@josevalim
Copy link
Member

❤️ 💚 💙 💛 💜

josevalim pushed a commit that referenced this pull request Jul 18, 2018
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants