Subscribe to access all episodes. View plans →

#175: Credo

Published November 27, 2023

Credo

Follow along with the episode starter on GitHub


Credo is an Elixir package that runs static code analysis on your project that’s focused on teaching and helps keep your code consistent. For example, Credo can show you refactoring opportunities, highlight complex code fragments, and warn you about common mistakes. And it has several different editor integrations to help you run to Credo in the background. To see how it works, let’s use it in a project.

Let’s open our project. It has a single module with a couple functions that are used to generate long and short passwords using eff_pass. Now if you’re familiar with Elixir you might be able to spot a couple mistakes in our code. But if you’re new to Elixir or programming in general, you might not catch the issues especially since the code works and returns short and long passwords. Let’s see how Credo can help us improve this code.

We’ll go to Hex and grab the credo config. Then let’s open our project’s Mixfile and add credo to the list of dependencies. We’ll only need credo in our development and test environments, so let’s restrict it to that. We don’t need credo at runtime, so let’s include runtime: false.

mix.exs

...

defp deps do
...
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
...
end

...

With that added let’s go to the command line and run mix deps.get.

$ mix deps.get
...

And great, now we can run Credo, which we can do by calling mix credo. When we do, we see that credo gives us a summary of the issues it found. It looks like we have two issues with our code readability - our function names need to be written in snake case. And one warning, where we have an unused return value for a string function.

$ mix credo
Checking 3 source files ...

  Code Readability
┃
┃ [R] ↗ Function/macro/guard names should be written in snake_case.
┃       lib/teacher.ex:11:7 #(Teacher.longPASS)
┃ [R] ↗ Function/macro/guard names should be written in snake_case.
┃       lib/teacher.ex:7:7 #(Teacher.shortPass)

  Warnings - please take a look
┃
┃ [W] ↗ There should be no unused return values for String functions.
┃       lib/teacher.ex:21:5 #(Teacher.gen_pass)

Please report incorrect results: https://github.com/rrrene/credo/issues

Analysis took 0.1 seconds (0.07s to load, 0.08s running 55 checks on 3 files)
5 mods/funs, found 1 warning, 2 code readability issues.

Showing priority issues: ↑ ↗ →  (use `mix credo explain` to explain issues, `mix credo --help` for options).

credo assigns a priority to the issues it finds, which it indicates with an arrow next to the issue. There are a lot of different options you can use with credo, which you can see listed in the documentation.

Let’s go ahead and run credo again using the --strict option. This will show all issues, including the lower-priority ones. With the strict option, we get one additional issue returned - we have an extra blank line in our module.

$ mix credo --strict
Checking 3 source files ...

  Code Readability
┃
┃ [R] ↗ Function/macro/guard names should be written in snake_case.
┃       lib/teacher.ex:11:7 #(Teacher.longPASS)
┃ [R] ↗ Function/macro/guard names should be written in snake_case.
┃       lib/teacher.ex:7:7 #(Teacher.shortPass)
┃ [R] ↘ There should be no more than 1 consecutive blank lines.
┃       lib/teacher.ex:25 #(Teacher.gen_pass)

  Warnings - please take a look
┃
┃ [W] ↗ There should be no unused return values for String functions.
┃       lib/teacher.ex:21:5 #(Teacher.gen_pass)

Please report incorrect results: https://github.com/rrrene/credo/issues

Analysis took 0.1 seconds (0.06s to load, 0.07s running 67 checks on 3 files)
5 mods/funs, found 1 warning, 4 code readability issues.

Use `mix credo explain` to explain issues, `mix credo --help` for options.

If credo returns an issue, like it did for our project here, and you want to get more information about it you can run mix credo explain with the check name or the path of the issue including the line.

Let’s see what it says for our first issue. And credo gives us a pretty detailed explanation of what the issue is on that line of code. We’re not declaring our function in snake case and “Function, macro, and guard names are always written in snake_case in Elixir.”

$ mix credo explain lib/teacher.ex:11:7
Teacher
┃
┃   [R] Category: readability
┃    ↗  Priority: high
┃
┃       Function/macro/guard names should be written in snake_case.
┃       lib/teacher.ex:11:7 (Teacher.longPASS)
┃
┃    __ CODE IN QUESTION
┃
┃     9   end
┃    10
┃    11   def longPASS do
┃             ^^^^^^^^
┃    12     gen_pass(word_length: 8, list: :long)
┃    13   end
┃
┃    __ WHY IT MATTERS
┃
┃       Function, macro, and guard names are always written in snake_case in Elixir.
┃
┃           # snake_case
┃
┃           def handle_incoming_message(message) do
┃           end
┃
┃           # not snake_case
┃
┃           def handleIncomingMessage(message) do
┃           end
┃
┃       Like all `Readability` issues, this one is not a technical concern.
┃       But you can improve the odds of others reading and liking your code by making
┃       it easier to follow.
┃
┃    __ CONFIGURATION OPTIONS
┃
┃       To configure this check, use this tuple
┃
┃         {Credo.Check.Readability.FunctionNames, <params>}
┃
┃       with <params> being false or any combination of these keywords:
┃
┃         allow_acronyms:  Allows acronyms like HTTP or OTP in function names.

Then it gives us some configuration options, let’s look at that now. To customize credo we’ll need to generate a .credo.exs configuration file with mix credo gen.config.

$ mix credo gen.config
* creating .credo.exs

It created the file so let’s go to our project and open it. Now there are a lot of different ways you can customize credo to fit your use case. We won’t get into all of them here, but you can read more about them in Credo’s docs.

Previously we ran credo --strict - let’s customize credo to always run with the strict option. We’ll scroll down and all we need to do to use that is to set strict: true.

If we scroll down a bit more, we see all the checks Credo performs are done with these credo check modules. If you don’t want to run a specific check for your project you can disable them here. In fact, let’s disable the check module that gave us the issue about the extra blank line in our code. We’ll find the RedundantBlankLines module and we can disable it by replacing the second element with false.

.credo.exs

...
strict: true,
...
{Credo.Check.Readability.RedundantBlankLines, false},
...

When we run $ mix credo it will use the settings from our configuration file. We’ll go back to the command line and run mix credo.

Great it didn’t include an issue for our extra blank line. Now let’s fix the issues that were returned. We’ll go to our Teacher module and we’ll update the function that generates the short password to be snake case as well as the function that generates a long password. Then below in the gen_pass function, let’s remove the line where we have an unused value from our String function, and let’s clean up our function and fix that to be an option that the EFFPass module uses.

lib/teacher.ex

defmodule Teacher do
  @moduledoc """
  A module that uses `eff_pass` for generating passwords
  using EFF's word lists using
  """

  def short_pass do
    gen_pass(word_length: 4, list: :short)
  end

  def long_pass do
    gen_pass(word_length: 8, list: :long)
  end

  defp gen_pass(word_length: word_length, list: list) do
    [sep: "-"]
    |> Keyword.merge(words: word_length)
    |> Keyword.merge(list: list)
    |> EFFPass.gen()
  end


end

With that, let’s save our module and go back to the command line. If we run credo again. Great, it didn’t find any issues to report.

$ mix credo
Checking 3 source files ...

Please report incorrect results: https://github.com/rrrene/credo/issues

Analysis took 0.09 seconds (0.05s to load, 0.04s running 66 checks on 3 files)
5 mods/funs, found no issues.

Use `mix credo explain` to explain issues, `mix credo --help` for options.

Perfect, in hardly any time we were able to add Credo, customize it, and use it in our project.

© 2024 HEXMONSTER LLC