Search documentation of Metastatic

# Metastatic.Analysis.Cohesion (Metastatic v0.13.2)

View Source

Cohesion analysis for containers (modules/classes).

Measures how well the members (methods/functions) of a container work together. High cohesion indicates that members are closely related and work toward a common purpose, which is a desirable property in object-oriented design.

## Supported Metrics

### LCOM (Lack of Cohesion of Methods)

Measures the number of disjoint sets of methods. Lower is better.

- LCOM = 0: Perfect cohesion (all methods share state)
- LCOM > 0: Poor cohesion (methods form disconnected groups)

### TCC (Tight Class Cohesion)

Ratio of directly connected method pairs. Range: 0.0-1.0, higher is better.

- TCC = 1.0: All methods directly share state
- TCC > 0.5: Good cohesion
- TCC < 0.3: Poor cohesion

### LCC (Loose Class Cohesion)

Ratio of directly or indirectly connected method pairs. Range: 0.0-1.0.

- LCC >= TCC always
- High LCC but low TCC: Methods connected through intermediaries

## Algorithm

1. Extract all methods/functions from container
2. For each method, identify which instance variables it accesses
3. Build a connection graph between methods based on shared variables
4. Calculate LCOM (number of disconnected components)
5. Calculate TCC (direct connections / total possible pairs)
6. Calculate LCC (transitive closure / total possible pairs)

## Examples

    # High cohesion - all methods use shared state
    ast = {:container, :class, "BankAccount", %{}, [
      {:function_def, :public, "deposit", ["amount"], %{},
       {:augmented_assignment, :+, {:attribute_access, {:variable, "self"}, "balance"}, {:variable, "amount"}}},
      {:function_def, :public, "withdraw", ["amount"], %{},
       {:augmented_assignment, :-, {:attribute_access, {:variable, "self"}, "balance"}, {:variable, "amount"}}},
      {:function_def, :public, "get_balance", [], %{},
       {:attribute_access, {:variable, "self"}, "balance"}}
    ]}

    doc = Document.new(ast, :python)
    {:ok, result} = Cohesion.analyze(doc)

    result.lcom           # => 0 (perfect cohesion)
    result.tcc            # => 1.0 (all methods connected)
    result.assessment     # => :excellent

    # Low cohesion - methods don't share state
    ast = {:container, :class, "Utilities", %{}, [
      {:function_def, :public, "format_date", ["date"], %{}, ...},
      {:function_def, :public, "calculate_tax", ["amount"], %{}, ...},
      {:function_def, :public, "send_email", ["to", "msg"], %{}, ...}
    ]}

    {:ok, result} = Cohesion.analyze(doc)
    result.lcom           # => 3 (three disjoint methods)
    result.tcc            # => 0.0 (no shared state)
    result.assessment     # => :very_poor

## Summary

### Functions

analyze(doc)

Analyze cohesion of a container (module/class/namespace).

analyze!(doc)

Analyze cohesion of a container (module/class/namespace).

## Functions

# analyze(doc)

    @spec analyze(Metastatic.Document.t()) :: {:ok, term()} | {:error, term()}

Analyze cohesion of a container (module/class/namespace).

Returns `{:ok, result}` if the AST contains a container, or `{:error, reason}` otherwise.

## Examples

    iex> ast = {:container, :class, "Calculator", %{}, [
    ...>   {:function_def, :public, "add", ["x"], %{},
    ...>    {:augmented_assignment, :+, {:attribute_access, {:variable, "self"}, "total"}, {:variable, "x"}}},
    ...>   {:function_def, :public, "get_total", [], %{},
    ...>    {:attribute_access, {:variable, "self"}, "total"}}
    ...> ]}
    iex> doc = Metastatic.Document.new(ast, :python)
    iex> {:ok, result} = Metastatic.Analysis.Cohesion.analyze(doc)
    iex> result.lcom
    0
    iex> result.tcc
    1.0

# analyze!(doc)

    @spec analyze!(Metastatic.Document.t()) :: term()

Analyze cohesion of a container (module/class/namespace).

Returns `{:ok, result}` if the AST contains a container, or `{:error, reason}` otherwise.

## Examples

    iex> ast = {:container, :class, "Calculator", %{}, [
    ...>   {:function_def, :public, "add", ["x"], %{},
    ...>    {:augmented_assignment, :+, {:attribute_access, {:variable, "self"}, "total"}, {:variable, "x"}}},
    ...>   {:function_def, :public, "get_total", [], %{},
    ...>    {:attribute_access, {:variable, "self"}, "total"}}
    ...> ]}
    iex> doc = Metastatic.Document.new(ast, :python)
    iex> {:ok, result} = Metastatic.Analysis.Cohesion.analyze(doc)
    iex> result.lcom
    0
    iex> result.tcc
    1.0

Unlike not-banged version, this one either returns a result or raises