Define module aliases at the top of the file instead of using fully qualified nested module names in function bodies. Improves code readability and maintainability while addressing Credo style warnings.
When using modules with long, nested names multiple times in your code, Elixir's alias directive allows you to create shorter references at the top of the module. This improves code readability, reduces duplication, and makes refactoring easier. Credo warns when nested modules are called directly in function bodies instead of being aliased.
defmodule MyApp.Service do
# ❌ BAD: No aliases, long nested module names in functions
def fetch_data do
MyApp.ExternalServices.API.Client.fetch()
end
def process_data(data) do
MyApp.ExternalServices.API.Parser.parse(data)
end
def validate_result(result) do
MyApp.ExternalServices.API.Validator.validate(result)
end
end
# ❌ BAD: Nested module call in private function
defmodule Explorer.Chain.Metrics.Queries.IndexerMetrics do
defp multichain_search_enabled? do
Explorer.MicroserviceInterfaces.MultichainSearch.enabled?()
end
end
defmodule MyApp.Service do
# ✅ GOOD: Aliases defined at module top
alias MyApp.ExternalServices.API.Client
alias MyApp.ExternalServices.API.Parser
alias MyApp.ExternalServices.API.Validator
def fetch_data do
Client.fetch()
end
def process_data(data) do
Parser.parse(data)
end
def validate_result(result) do
Validator.validate(result)
end
end
# ✅ GOOD: Module aliased at the top
defmodule Explorer.Chain.Metrics.Queries.IndexerMetrics do
alias Explorer.MicroserviceInterfaces.MultichainSearch
defp multichain_search_enabled? do
MultichainSearch.enabled?()
end
end
# ✅ Simple alias - uses last segment as the name
alias MyApp.Services.EmailService
EmailService.send()
# ✅ Group related modules
alias MyApp.Models.{User, Post, Comment}
User.find(id)
Post.create(attrs)
Comment.list_by_post(post_id)
# ✅ Use custom name to avoid conflicts or for clarity
alias MyApp.External.API.Client, as: ExternalClient
alias MyApp.Internal.API.Client, as: InternalClient
ExternalClient.request()
InternalClient.request()
# ✅ Common aliasing pattern for nested structures
alias MyApp.Services.{
Authentication,
Authorization,
Notification
}
defmodule Explorer.Chain.Metrics.Queries.IndexerMetrics do
import Ecto.Query
alias Ecto.Adapters.SQL
alias Explorer.Chain.Address.TokenBalance
alias Explorer.Repo
# No alias for MultichainSearch
defp multichain_search_enabled? do
# ⚠️ Credo warning: Nested modules could be aliased
Explorer.MicroserviceInterfaces.MultichainSearch.enabled?()
end
defp check_feature_x do
Explorer.MicroserviceInterfaces.MultichainSearch.feature_x_enabled?()
end
end
defmodule Explorer.Chain.Metrics.Queries.IndexerMetrics do
import Ecto.Query
alias Ecto.Adapters.SQL
alias Explorer.Chain.Address.TokenBalance
alias Explorer.MicroserviceInterfaces.MultichainSearch
alias Explorer.Repo
# ✅ Module aliased at top, cleaner function bodies
defp multichain_search_enabled? do
MultichainSearch.enabled?()
end
defp check_feature_x do
MultichainSearch.feature_x_enabled?()
end
end
# ✅ OK: Single use of a module - aliasing adds noise
def one_time_call do
MyApp.RarelyUsed.Module.function()
end
# ✅ OK: Very short module name
def use_map do
Map.get(data, :key)
end
# ✅ OK: Kernel or Elixir standard library
def use_enum do
Enum.map(list, &process/1)
end
Follow this conventional order for imports and aliases:
defmodule MyApp.Service do
# 1. Use statements
use GenServer
# 2. Import statements
import Ecto.Query
# 3. Alias statements (alphabetically)
alias Ecto.Adapters.SQL
alias MyApp.Models.User
alias MyApp.Services.{EmailService, SmsService}
# 4. Require statements
require Logger
end
[D] ↘ Nested modules could be aliased at the top of the invoking module.
alias directive at the top of the modulemix credo to verify the warning is resolvedCredo.Check.Readability.AliasOrder - Checks alias alphabetical orderCredo.Check.Readability.ModuleDoc - Ensures modules have documentationCredo.Check.Design.AliasUsage - Reports nested module usage