{"id":5261,"date":"2016-03-31T11:20:07","date_gmt":"2016-03-31T14:20:07","guid":{"rendered":"http:\/\/blog.plataformatec.com.br\/?p=5261"},"modified":"2016-03-31T15:38:25","modified_gmt":"2016-03-31T18:38:25","slug":"inspecting-changing-and-debugging-elixir-project-dependencies","status":"publish","type":"post","link":"http:\/\/blog.plataformatec.com.br\/2016\/03\/inspecting-changing-and-debugging-elixir-project-dependencies\/","title":{"rendered":"Inspecting, changing and debugging Elixir project dependencies"},"content":{"rendered":"

You have probably heard that Elixir is very explicit and I\u2019d say the same!<\/p>\n

One of the things I really like in Elixir projects is that its dependencies are all explicitly included in the deps\/<\/code> directory. Every time we\u2019re curious about how a dependency works, we can just look at deps\/lib-name<\/code>.<\/p>\n

After working on a project for a while, I\u2019ve noticed a strange behavior in one of our dependencies. I’ve opened the deps\/lib-name<\/code> directory in my editor, inserted a couple IO.inspect<\/code> calls, and recompiled my dependencies with:<\/p>\n

mix deps.compile\n<\/code><\/pre>\n

That seems logical, doesn\u2019t it? For my surprise, I didn\u2019t get the expected behavior. The reason is straight-forward. Elixir projects (and its dependencies) are by default compiled for dev<\/code>, test<\/code> and prod<\/code> environments. These compiled files are located in _build\/<\/code>, in a directory that holds the environment name (_build\/dev\/<\/code>, _build\/test\/<\/code> and _build\/prod\/<\/code>). Accessing the applied changes in the source code depends on which environment we\u2019re running it.<\/p>\n

The kind of task we execute is deterministic. Running a test will make our _build\/test\/<\/code> compiled files to be used, just like iex -S mix<\/code> would use build\/dev\/<\/code> files and so on.<\/p>\n

What I did before would work if I tried to call the function I was inspecting through iex -S mix<\/code>. That\u2019s only because Elixir\u2019s default environment is dev<\/code>. In order to make those changes to be visible in my tests, I\u2019d have to:<\/p>\n

MIX_ENV=test mix deps.compile\n<\/code><\/pre>\n

There\u2019s a simple test we can run to understand this better:<\/p>\n

    \n
  1. Create a simple Elixir project with mix new project<\/code><\/li>\n
  2. Run iex -S mix<\/code><\/li>\n
  3. Take a look at the _build<\/code> directory and notice that we now have a _build\/dev<\/code> directory with that project’s compiled file<\/li>\n
  4. Run mix test<\/code> and notice that we now have a _build\/test<\/code><\/li>\n<\/ol>\n

    Using :path<\/code> option<\/h2>\n

    Instead of running mix deps.compile<\/code> for every change, there is a more convenient alternative.<\/p>\n

    When we declare our dependencies in the mix.exs<\/code> file we need to give it the library name and its version. We can also give it some extra options, among them there is a specific option that will help us when debugging dependencies: path<\/code>.<\/p>\n

      defp deps do\n    [{:plug, path: \"deps\/plug\"},\n     ...]\n  end\n<\/code><\/pre>\n

    When we set :path<\/code>, our dependency will be automatically recompiled by our project, as mentioned in Mix.Tasks.Deps docs<\/a> (we can also access it through mix help deps<\/code>).<\/p>\n

    \n Path and in umbrella dependencies are automatically recompiled by the parent project whenever they change.<\/em><\/strong>\n<\/p><\/blockquote>\n

    This way, every time I make a change and run a Mix task like mix test<\/code> or iex -S mix<\/code>, the dependency will be recompiled without having to run the compile task over and over again. With the path<\/code> option we can also omit the version because it’ll be retrieved from the project being addressed.<\/p>\n

    An important consideration here is that we can inform any path in this option, it doesn\u2019t need to be a source code in the deps\/<\/code> directory. It could, for example, point to a checkout of a dependency in our machine. This is an excellent option when we\u2019re working on an open source project. We can test the changes we intend to submit (or to find an issue) inside a real project more easily.<\/p>\n

    A dependency of other dependencies<\/h2>\n

    We know that Phoenix Framework uses Plug<\/code> for managing its requests but it\u2019s not listed in our project dependencies. That\u2019s because Plug is a Phoenix dependency<\/a>.<\/p>\n

    In order to inspect Plug<\/code> we\u2019d have to include it on our deps<\/code> function and use the override: true<\/code> option. Otherwise Mix will warn us that there is a dependency conflict.<\/p>\n

      defp deps do\n    [{:phoenix, \"~> 1.1.4\"},\n     {:postgrex, \">= 0.0.0\"},\n     {:phoenix_ecto, \"~> 2.0\"},\n     {:phoenix_html, \"~> 2.4\"},\n     {:phoenix_live_reload, \"~> 1.0\", only: :dev},\n     {:cowboy, \"~> 1.0\"},\n     {:plug, path: \"deps\/plug\", override: true}]\n  end\n<\/code><\/pre>\n

    Conclusion<\/h2>\n

    I believe that Elixir has already proven that explicitness is a great asset. Keeping project’s dependencies in deps\/<\/code> has already proved useful when searching for code and documentation.<\/p>\n

    In case you find a bug in any of your dependencies, we strongly recommend that you submit a pull request back to its repository. You\u2019ll help other developers that are going through the same issue and you’ll he the community growth.<\/p>\n

    What about you? Are there any tips you\u2019d like to share for debugging Elixir dependencies?<\/p>\n


    \n\"Subscribe
    \n<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"

    You have probably heard that Elixir is very explicit and I\u2019d say the same! One of the things I really like in Elixir projects is that its dependencies are all explicitly included in the deps\/ directory. Every time we\u2019re curious about how a dependency works, we can just look at deps\/lib-name. After working on a … \u00bb<\/a><\/p>\n","protected":false},"author":38,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[247,246,143,245],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/5261"}],"collection":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=5261"}],"version-history":[{"count":9,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/5261\/revisions"}],"predecessor-version":[{"id":5264,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/5261\/revisions\/5264"}],"wp:attachment":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=5261"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=5261"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=5261"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}