--- name: code-quality description: Use when refactoring for duplication, complexity, or dead code — includes the plugin's on-demand analysis scripts. file_patterns: - "**/*.ex" - "**/*.heex" auto_suggest: true --- # Code Quality Automation Automated detection of code quality issues in Elixir projects. These checks run automatically via hooks when files are written, and can be run on-demand for full project analysis. ## RULES — Follow these with no exceptions 1. **Duplicated functions must be extracted** — when 2+ modules share >70% identical function implementations, create a shared module 2. **Functions must stay below ABC complexity 30** — break complex functions into smaller helpers with single responsibilities 3. **Unused private functions must be removed** — dead code increases maintenance burden and confusion 4. **Duplicated templates must become components** — when 2+ HEEx files share >40% identical markup, extract to a function component 5. **Run full analysis before major refactors** — use `run_analysis.sh` to establish a baseline before and after 6. **Address duplication before complexity** — extracting shared code often reduces complexity as a side effect 7. **Prefer composition over inheritance** — extract shared functions into modules imported/used where needed, not into base modules --- ## What Gets Detected ### Code Duplication Detects when the same function appears in multiple modules with >70% body similarity. **How it works:** AST-based analysis parses function bodies and compares them using trigram similarity. Functions with the same name, arity, and similar bodies are flagged. **Example output:** ``` Duplication Detected Function `format_time/1` (85% similar) lib/app_web/live/cycle_time.ex:45 lib/app_web/live/lead_time.ex:52 Suggestion: Extract to a shared module ``` **How to fix:** ```elixir # Create: lib/app_web/live/helpers.ex defmodule AppWeb.Live.Helpers do def format_time(%Decimal{} = seconds) do seconds |> Decimal.to_float() |> format_time() end def format_time(seconds) when is_number(seconds) do # shared formatting logic end end # In each LiveView: import AppWeb.Live.Helpers, only: [format_time: 1] ``` ### ABC Complexity Measures function complexity using the ABC metric (Assignments, Branches, Conditions). - **A (Assignments):** `=` operators - **B (Branches):** `case`, `cond`, `if`, `unless`, `with`, `->` clauses - **C (Conditions):** `&&`, `||`, `and`, `or`, `==`, `!=`, `>`, `<`, `>=`, `<=`, `when` guards **ABC = sqrt(A² + B² + C²)** — threshold is 30. **Example output:** ``` High Complexity Detected Function `calculate_trend_line/1` — ABC complexity 41 (threshold: 30) lib/app_web/live/helpers.ex:45 Suggestion: Break into smaller functions with single responsibilities ``` **How to fix:** ```elixir # Before: one large function (complexity 41) def calculate_trend_line(data) do # 50 lines of assignments, branches, conditions end # After: composed smaller functions (complexity <20 each) def calculate_trend_line(data) do sums = calculate_regression_sums(data) slope = calculate_slope(sums) intercept = calculate_intercept(sums, slope) build_trend_points(data, slope, intercept) end ``` ### Unused Private Functions Detects `defp` functions that are defined but never called within the module. **Example output:** ``` Unused Private Functions `old_format_date` defined at line 123 but never called Suggestion: Remove if no longer needed ``` **Common after refactoring** — when you extract code to a shared module, the original private functions may become dead code. ### Template Duplication Detects when HEEx templates in the same directory share >40% identical markup. **Example output:** ``` Template Duplication Detected 86 identical lines (72%) between: cycle_time.html.heex lead_time.html.heex Suggestion: Extract shared markup to a function component ``` **How to fix:** ```elixir # Create a function component for the shared markup defmodule AppWeb.Live.Components do use Phoenix.Component def metric_filters(assigns) do ~H"""
""" end end ``` --- ## Running Analysis ### Automatic (via hooks) Code quality checks run automatically when files are written or edited: - `.ex`/`.exs` files trigger duplication, complexity, and unused function checks - `.heex` files trigger template duplication checks ### On-Demand (full project) Run a complete analysis from a checkout of this repo: ```bash bash scripts/run_analysis.sh ``` Or target specific checks: ```bash # Single file analysis elixir scripts/code_quality.exs all lib/app_web/live/my_live.ex # Specific check elixir scripts/code_quality.exs complexity lib/app_web/live/my_live.ex elixir scripts/code_quality.exs duplication lib/app_web/live/my_live.ex elixir scripts/code_quality.exs unused lib/app_web/live/my_live.ex # Scan entire lib/ directory elixir scripts/code_quality.exs scan lib/ ``` When installed as a plugin, the scripts live inside the plugin install directory rather than at a fixed path in the project — run the commands above from a checkout of this repo instead. --- ## Testing For testing guidance, see `testing-essentials`. When writing tests for refactored shared modules, ensure: - Original test coverage is maintained - New shared module has its own test file - All callers still pass their tests after extraction