···11+---
22+title: "Let's talk about `application/0`"
33+date: 2019-07-26T11:36:01+02:00
44+description: |
55+ Have you ever thought about that one simple function in your `mix.exs`? It
66+ comes out as quite powerful and useful place for storing configuration and
77+ post-launch scripts.
88+tags:
99+ - elixir
1010+ - erlang
1111+ - beam
1212+ - programming
1313+---
1414+1515+When you start your new Elixir project via `mix new my_awesome_project` you will
1616+end with something like this in `mix.exs`:
1717+1818+```elixir
1919+defmodule MyAwesomeProject.Mixfile do
2020+ use Mix.Project
2121+2222+ def config do
2323+ [
2424+ name: :my_awesome_project,
2525+ # …
2626+ deps: deps()
2727+ ]
2828+ end
2929+3030+ def application do
3131+ [
3232+ extra_applications: [:logger]
3333+ ]
3434+ end
3535+3636+ defp deps do
3737+ [
3838+ # …
3939+ ]
4040+ end
4141+end
4242+```
4343+4444+And in most cases you will focus on `deps/0`, sometimes on `config/0`, but the
4545+`application/0` you will almost never touch, and if you do, you probably will only
4646+need it to add new entry in `:extra_applications` or sometimes
4747+`:included_applications`. Except for, that this function interns are terra
4848+incognita, a place where you never look unless you are forced to, like "Read
4949+it later" list in Safari. This is sad, as it is quite powerful and useful
5050+piece of code.
5151+5252+However first things first.
5353+5454+## What `application/0` is for?
5555+5656+In Erlang the running system is built from applications. Those applications are
5757+like processes in your system managed by your system supervisor (SysV, systemd,
5858+OpenRC, launchd, etc.). They are launched either during VM startup or on
5959+direct user request via `Application.start/1-2` and its family. Starting
6060+this application is described in `my_awesome_app.app` file which is commonly
6161+generated by the build system from the template. In Rebar3 projects this
6262+template is `src/appname.app.src` and in Elixir it's the return value of the
6363+named `application/0` function. This generated file is known as [Application
6464+Resource File][app file]. It is just tuple in form of `{:application,
6565+:my_awesome_app, opts}` where `opts` is a keyword list of additional properties
6666+(to be exact it's output of the `application/0` function).
6767+6868+Two of those optional fields are quite known in the Elixir community:
6969+7070+- `:mod` which is a tuple `{module(), term()}` containing the starting point
7171+ of our application; in most cases this is the module that will return main
7272+ supervisor of the application.
7373+- `:applications` contains all applications required by our application; younger
7474+ Elixir developers possibly never seen that as since version 1.5 this field
7575+ is automatically filled by parsing `:deps`, though we still can add entries
7676+ there via `:extra_applications`
7777+7878+There are also few Elixir specific fields, sometimes used in larger projects:
7979+8080+- `:extra_applications` - those should be included in the release
8181+ and automatically started before running current application; but aren't in the
8282+ dependencies list because, for example, are in default distribution, for
8383+ example `logger` or `inets`.
8484+- `:included_applications` - applications which should be included in the
8585+ release, but not automatically started on boot.
8686+8787+Wait, there is more!
8888+8989+Unfortunately not all of the highly useful keys are used/known in the community.
9090+9191+## Application environment
9292+9393+For some reason everyone calls it configuration, so if you are familiar with
9494+`config/config.exs` and for some reason you decided to go [against the *Library
9595+Guidelines*](guidelines) and you have decided to use application environment for
9696+configuring your code (there are reason to do so, even when you publish your
9797+code as a "library", see `lager` or `opencensus`) then you will soon find that
9898+putting configuration in your's library `config/config.exs` do not matter much
9999+in it's dependants. You have 2 possibilities how to solve that:
100100+101101+- Use `Application.get_env/3` and define your "default" as a 3rd argument.
102102+- Use `:env` to set data that should be loaded to application environment by
103103+ default.
104104+105105+Be wary that the second option works only for current application, so you
106106+cannot configure other applications (for example `logger`) there. *But what is
107107+the point?* You may ask, and I found one. If you want to use default
108108+`sys.config` file for configuring your application then sometimes few pointless
109109+configuration option can land there, like `:ecto_repos` variable which truly
110110+doesn't matter much in production as it's only used by Ecto's Mix tasks. What
111111+I do is to add new entry in `application/0` with:
112112+113113+```elixir
114114+env: [
115115+ ecto_repos: [MyAwesomeApp.Repo]
116116+]
117117+```
118118+119119+And call it a day. Now I can focus on keeping **real** configuration options in
120120+`config/config.exs` and remove unneeded fields from there. But remember that you
121121+still can override these values by setting them in `sys.config` if needed, so
122122+this is pure win for me.
123123+124124+## Start phases
125125+126126+Application configuration also allows you to define additional pieces of code to
127127+be run after your application started. For example imagine situation when you
128128+want to send Slack notification that given node started and is ready to work.
129129+You can do it via temporary task in `Supervisor.init/2` by defining child list
130130+like:
131131+132132+```elixir
133133+[
134134+ MyApp.Repo,
135135+ MyApp.Worker,
136136+ {Task, &send_slack_notification/0}
137137+]
138138+```
139139+140140+Alternatively you can use `:start_phases` in `application/0`:
141141+142142+```elixir
143143+start_phases: [
144144+ notify: []
145145+]
146146+```
147147+148148+And then define in your `Application` module function `start_phase/3`:
149149+150150+```elixir
151151+def start_phase(:notify, :normal, opts) do
152152+ :ok = send_slack_notification()
153153+end
154154+```
155155+156156+Where 1st argument will be the name of the phase, 2nd will be start type the
157157+same as in [`Application.start/2` callback](https://hexdocs.pm/elixir/Application.html#c:start/2),
158158+and 3rd is the value passed in `:start_phases`.
159159+160160+The awesome part there is that `start_phase/3` is called not only for current
161161+application, but all of it's dependencies as well.
162162+163163+## Registered names
164164+165165+This is one of the things that had more sense in Erlang world than in Elixir,
166166+but by being good citizen we should use it as well. This is a nice solution for
167167+lack of namespacing in Erlang - it allowed release tools to detect collisions in
168168+named processes. This is simple list of atoms that contain all names that are
169169+globally registered by this application. Example form [Elixir's
170170+Logger](https://github.com/elixir-lang/elixir/blob/ee9f38635e9a6c816adb575fc9431ded49be8032/lib/logger/mix.exs#L14):
171171+172172+```elixir
173173+registered: [Logger, Logger.BackendSupervisor, Logger.Supervisor, Logger.Watcher]
174174+```
175175+176176+Unfortunately Phoenix do not use this field itself and do not suggest using one
177177+in it's default project generator. But in general it's good practise.
178178+179179+## Summary
180180+181181+There is much more in application configuration to what most Elixir code is
182182+using, it is worth sometimes to read how your application is defined and ran.
183183+For more information about generating application description file you can check
184184+out [`mix help compile.app`](https://hexdocs.pm/mix/Mix.Tasks.Compile.App.html).
185185+186186+[app file]: http://www.erlang.org/doc/design_principles/applications.html#application-resource-file
187187+[guidelines]: https://hexdocs.pm/elixir/library-guidelines.html