Elixir
Interview: Jeremy Huffman, Dialyxir
Dialyxir is an Elixir library that helps programmers use dialyzer, the Erlang static analysis tool. Dialyxir and dialyzer combine to identify type errors, dead code, and unnecessary tests.
I recently emailed some questions to Jeremy Huffman, maintainer of the Dialyxir project. Here's our correspondence.
For the people that don’t know you, could you tell us a bit about yourself?
I've been working as a software developer for just over twenty years. Professionally I have experience in popular enterprise industry languages such as C#, Java and C++ but I've always programmed for fun with side projects / open source and in those contexts have preferred other languages including Ruby, Elixir and Haskell. In 2017 I joined a startup using Elixir and Phoenix and am still thrilled to work in this language every day. I work in Charlotte, NC and live nearby with my wife and kids.
How did Dialyxir come into existence?
When I was first learning Elixir, the topic of Dialyzer came up on the Elixir mailing list and someone pasted a couple of lines of shell input they used to invoke the Erlang dialyzer in their Elixir project. I decided to make a mix task that would do the same thing and manage the configuration (such as apps to include in the PLT) in the project's mix file. I initially created it in the style of a glorified shell script that took configuration inputs from the mix project file and then shelled out to the dialyzer CLI. I put it up on Github but didn't really consider it complete enough for general usage and so I didn't announce it, but a week later I got a pull request and the PRs never stopped coming. I eventually did an overhaul / rewrite— back in 2016— but it is still the case that most of the functionality has come from small changes submitted in pull requests.
What connection do you feel with the Erlang community? What kind of dialogue is there between your project and that community?
When I first learned Elixir (early 2013) there were not any Elixir books yet and while there were some good Elixir resources they were mostly introductory. I found it super helpful to read "Learn You Some Erlang" and learn Erlang well enough to read it comfortably. That book is where I first learned about Dialyzer. Erlang has fantastic documentation which I've taken advantage of many times. To be honest though I haven't had much other interaction with the Erlang community other than through a few bug tickets. In those cases I've found them to be extremely helpful and welcoming. The Erlang core team is superb and very responsive, as are the community mailing lists.
Why would an Elixir team consider adding Dialyxir to their project?
At a minimum it is an interest in good hygiene— for similar reasons that you
might have a CI suite that runs a linter like Credo, compiles with warnings as
errors, or run a mix format --check-formatted
, you might want to run dialyzer
on your code with every push. If you are doing TDD or at least writing lots of
tests you may not see dialyzer discover very many bugs but it will identify
cases where you have unreachable code such as a pattern that is covered by a
previous clause or you may have uncommon branches of code, particularly in
error handlers that will fail at runtime and aren't tested.
Describe an Elixir project where Dialyxir would be a useful addition. How does the team get the most out of it?
For libraries that you intend other people to use, I think it is important that
you use @spec
annotations in the public API because not only do they provide
great API documentation but that documentation will be checked statically; if
your actual implementation drifts from the @spec
dialyzer will catch it. In
those cases your tests may all pass (since you've updated them) and the code
may work just fine, but dialyzer will identify the incorrect specs so that you
can ensure the documentation matches.
For application projects it can be useful as well, and while it's good hygiene to have it in CI, it can also be a useful part of your personal development workflow. Sometimes it is easier to debug an issue by looking at a dialyzer error rather than a huge stack trace.
Are there projects where Dialyxir might be unnecessary? What are the tradeoffs?
Strictly speaking, it is never necessary— it is always optional. However, many mature projects in Elixir include specs for documentation, and when you do that then some means of running dialyzer is a really essential practice. I think one of the biggest reasons people may not use it is that the warnings are hard to understand, even if you have experience with a statically typed language. The work Andrew Summers did last year on pretty printing the terms for the dialyzer warnings (which you can see in the RC) has gone a long way to address this, and people who have only seen dialyzer output in the 0.5 version or below should take another look.
How does Dialyxir integrate with your personal coding workflow?
I most frequently use test driven development but sometimes I do type-driven development where the types and specs come first, then the implementation and tests. Sometimes I will write the specs before the function implementations, just to help me think through how the pieces of the module will fit together. Then as I'm implementing the functions I can run dialyzer continuously to make sure the code I've written fits into the types.
Dialyxir has a release candidate in production. What’s the timeline for 1.0? What changes can we expect?
We've had a RC out there for quite awhile so it's a great question. I think
we'll see 1.0 before the end of April. We had to run a pretty extended RC
period last year with the new pretty printing changes. Andrew wrote a custom
parser to take the Erlang-style terms that the dialyzer library returns (as
strings), and reformat it in the style that Elixir code is presented. For
example, Erlang would report an error related to an Elixir struct as something
like #{__struct__ => Elixir.MyApp.User ...}
and we want to see that in Elixir
as %User{...}
. Finding all the variations in how that string output could
come from dialyzer really required exposure to lots of real code in the
wild. That work settled in awhile ago but there are a few other changes we
decided to make part of the scope of the 1.0 release. Our goal is to take care
of all known breaking changes in that release.
If people want to get involved with Dialyxir, where should they start? What kind of help do you need from the open source community?
We have some issues tagged "Help Wanted" in the issue tracker; certainly those could be a good place to start, but we're always open to suggestions of new features/functionality as well. If you use Dialyxir and would like to see something a little different than it is today, feel free to open an issue to discuss it with us!
Photo by Louis Reed on Unsplash