| name | elixir-clause-grouping |
| description | Use when refactoring Elixir multi-clause functions, extracting helper functions, or fixing Credo readability warnings caused by placing `defp` helpers between clauses of the same function. Keeps function clauses contiguous and moves helpers below the full clause group. |
Overview
In Elixir modules, all clauses of the same function should stay together. Inserting a defp helper between clauses of a def or defp makes the function harder to read and can trigger Credo readability warnings. When shared logic needs to be extracted, keep the original clause group contiguous and place the helper after the full group.
When to Use
- When refactoring a multi-clause
def or defp
- When extracting duplicated logic from multiple function clauses
- When addressing Credo warnings about clause grouping or readability
- When editing controller, view, or context modules with several clauses of the same function
- During review when a helper was added in the middle of another function's clauses
Core Rule
- Keep all clauses of the same function contiguous
- Do not place
defp helpers between clauses of another function
- Extract shared logic into a helper placed after the full clause group
Anti-Pattern
def decoded_input_data(%Transaction{to_address: nil}, _, _, _, _), do: {:error, :no_to_address}
defp decode_input_data_with_fallback(data, abi, input, hash, skip_sig_provider?, options, methods_map, abi_map) do
...
end
def decoded_input_data(%Transaction{to_address: %NotLoaded{}}, _, _, _, _), do: {:error, :contract_not_verified, []}
This splits the decoded_input_data/5 clause group and makes the function harder to scan.
Preferred Pattern
def decoded_input_data(%Transaction{to_address: nil}, _, _, _, _), do: {:error, :no_to_address}
def decoded_input_data(%Transaction{to_address: %NotLoaded{}}, _, _, _, _), do: {:error, :contract_not_verified, []}
def decoded_input_data(%Transaction{to_address: %{smart_contract: smart_contract}} = transaction, skip_sig_provider?, options, methods_map, abi_map) do
...
end
defp decode_input_data_with_fallback(data, abi, input, hash, skip_sig_provider?, options, methods_map, abi_map) do
...
end
Refactoring Checklist
- Identify every clause of the function being edited.
- Keep those clauses adjacent to each other.
- Extract shared logic only after the full clause group.
- Re-check that no unrelated
def or defp appears inside the group.
- Run formatting after the refactor.
Notes
- This applies to both public and private multi-clause functions.
- If a helper is only used by one clause group, place it immediately after that group.
- Preserving clause grouping is preferred even when the extracted helper is small.