Ragex.Analysis.DependencyGraph
(Ragex v0.12.0)
View Source
Dependency analysis for module and function relationships.
Analyzes the dependency graph stored in the knowledge graph to:
- Detect circular dependencies
- Calculate coupling metrics (afferent, efferent, instability)
- Find unused modules
- Identify God modules (high coupling)
- Suggest decoupling opportunities
All analysis operates on the existing knowledge graph edges (:calls, :imports).
Summary
Functions
Calculates coupling metrics for all modules in the project.
Analyzes dependencies for all modules in the knowledge graph.
Analyzes a module comprehensively.
Calculates coupling metrics for a module.
Generates suggestions for decoupling the codebase.
Finds circular dependencies in the module dependency graph.
Finds "God modules" - modules with high coupling.
Finds modules that are not referenced by any other module.
Types
@type coupling_metrics() :: %{ afferent: non_neg_integer(), efferent: non_neg_integer(), instability: float() }
@type function_ref() :: {:function, module(), atom(), non_neg_integer()}
@type module_name() :: atom()
Functions
@spec all_coupling_metrics(keyword()) :: {:ok, [{module_name(), coupling_metrics()}]} | {:error, term()}
Calculates coupling metrics for all modules in the project.
Returns a map of module => coupling_metrics.
Parameters
opts: Keyword list of options:include_transitive- Include transitive dependencies (default: false):sort_by- Sort by:instability,:afferent,:efferent, or:name(default::instability):descending- Sort in descending order (default: true)
Returns
{:ok, [{module, metrics}]}- List of module-metrics tuples, sorted
Examples
{:ok, all_metrics} = all_coupling_metrics(sort_by: :instability)
Analyzes dependencies for all modules in the knowledge graph.
Convenience function that returns a comprehensive dependency analysis.
Examples
{:ok, analysis} = DependencyGraph.analyze_all_dependencies()
analysis.modules # => %{MyModule => %{dependencies: [...], ...}}
@spec analyze_module( module_name(), keyword() ) :: {:ok, map()} | {:error, term()}
Analyzes a module comprehensively.
Provides complete dependency analysis for a single module including:
- Coupling metrics (afferent, efferent, instability)
- Direct dependencies and dependents
- Circular dependency involvement
- God module status
- Function count and complexity indicators
Parameters
module: Module name atomopts: Keyword list of options:include_transitive- Include transitive dependencies (default: false):include_functions- Include function list (default: false):ai_insights- Use AI for architectural insights (default: from config)
Returns
{:ok, analysis}- Comprehensive module analysis map{:error, reason}- Error if module not found or analysis fails
Analysis Map Structure
%{
module: ModuleName,
exists: true,
coupling: %{afferent: 5, efferent: 3, instability: 0.375},
dependencies: [ModuleA, ModuleB],
dependents: [ModuleC, ModuleD],
function_count: 12,
in_cycles: [[ModuleA, ModuleB, ModuleName]],
is_god_module: false,
functions: [...] # if include_functions: true
}Examples
{:ok, analysis} = analyze_module(MyModule)
{:ok, analysis} = analyze_module(MyModule, include_transitive: true, include_functions: true)
@spec coupling_metrics( module_name(), keyword() ) :: {:ok, coupling_metrics()} | {:error, term()}
Calculates coupling metrics for a module.
Coupling metrics:
- Afferent coupling (Ca): Number of modules that depend on this module (incoming)
- Efferent coupling (Ce): Number of modules this module depends on (outgoing)
- Instability (I): Ce / (Ca + Ce) - ranges from 0 (stable) to 1 (unstable)
Parameters
module: Module name atomopts: Keyword list of options:include_transitive- Include transitive dependencies (default: false)
Returns
{:ok, metrics}- Coupling metrics map{:error, reason}- Error if module not found or analysis fails
Examples
{:ok, metrics} = coupling_metrics(MyModule)
# => %{afferent: 5, efferent: 3, instability: 0.375}
@spec decoupling_suggestions(keyword()) :: {:ok, [suggestion()]} | {:error, term()}
Generates suggestions for decoupling the codebase.
Analyzes the dependency graph to find:
- Circular dependencies that should be broken
- God modules that should be split
- Highly unstable modules that need stabilization
- Unused modules that can be removed
Returns
{:ok, [suggestion]}- List of decoupling suggestions{:error, reason}- Error if analysis fails
Examples
{:ok, suggestions} = decoupling_suggestions()
@spec find_cycles(keyword()) :: {:ok, [[module_name() | function_ref()]]} | {:error, term()}
Finds circular dependencies in the module dependency graph.
Returns a list of cycles, where each cycle is a list of module names forming a circular dependency. Uses depth-first search to detect cycles.
Parameters
opts: Keyword list of options:min_cycle_length- Minimum cycle length (default: 2):scope-:moduleor:function(default::module):limit- Maximum number of cycles to return (default: 100)
Returns
{:ok, [cycle]}- List of cycles found{:error, reason}- Error if analysis fails
Examples
# Find all module-level cycles
{:ok, cycles} = find_cycles()
# Find function-level cycles (minimum length 3)
{:ok, cycles} = find_cycles(scope: :function, min_cycle_length: 3)
@spec find_god_modules( non_neg_integer(), keyword() ) :: {:ok, [{module_name(), coupling_metrics()}]} | {:error, term()}
Finds "God modules" - modules with high coupling.
God modules are modules that have excessive dependencies or dependents, indicating potential design issues.
Parameters
threshold: Minimum total coupling (afferent + efferent) to be considered a God moduleopts: Keyword list of options:sort_by- Sort by:total,:afferent,:efferent, or:instability(default::total)
Returns
{:ok, [{module, metrics}]}- List of God modules with their metrics
Examples
# Find modules with total coupling >= 20
{:ok, god_modules} = find_god_modules(20)
@spec find_unused(keyword()) :: {:ok, [module_name()]} | {:error, term()}
Finds modules that are not referenced by any other module.
A module is considered unused if:
- No functions in the module are called by other modules
- The module is not imported/required/used by other modules
- The module is not an entry point (tests, mix tasks, etc.)
Parameters
opts: Keyword list of options:exclude_tests- Exclude test modules from results (default: true):exclude_mix_tasks- Exclude Mix tasks (default: true)
Returns
{:ok, [module_name]}- List of potentially unused modules{:error, reason}- Error if analysis fails
Examples
{:ok, unused} = find_unused()