Skip to content
dotnet-serena-analysis-patterns logo

Dotnet Serena Analysis Patterns

dotnet-serena-analysis-patterns

Code analysis patterns using Serena MCP for architecture validation and pattern detection

rudironsoni/Synaxis0installs2stars

SKILL.md

Full skill instructions

dotnet-serena-analysis-patterns

Analyze .NET codebases using Serena MCP's symbol-aware capabilities. Detect patterns, validate architecture, and understand code structure at the semantic level.

Trigger

Use when needing to:

  • Validate architectural patterns
  • Detect code smells and anti-patterns
  • Analyze dependencies and coupling
  • Understand project structure
  • Review for maintainability issues

Analysis Approach

Traditional Analysis Limitations

# Text-based analysis problems:
- Regex can't understand semantics
- False positives on similar names
- Misses relationships between symbols
- No type information
- Limited cross-file understanding

Symbol-Aware Analysis Benefits

# Serena advantages:
- Precise symbol identification
- Type hierarchy understanding
- Cross-reference tracking
- Semantic relationships
- Automated dependency mapping

Architecture Pattern Validation

Pattern 1: Layered Architecture Validation

Goal: Verify proper layer separation

# Step 1: Find domain layer types
serena_find_symbol: "MyApp.Domain.*"

# Step 2: Check domain references infrastructure
serena_find_referencing_symbols: "MyApp.Infrastructure.*"
# Should NOT reference Domain types in wrong direction

# Step 3: Validate dependency direction
# Domain -> Application -> Infrastructure
# NOT: Infrastructure -> Domain

Anti-pattern detection:

# Find infrastructure referencing domain
coupling = []
for infra_type in infrastructure_types:
    refs = serena_find_referencing_symbols(infra_type)
    for ref in refs:
        if "Domain" in ref:
            coupling.append((infra_type, ref))

if coupling:
    print("Violation: Infrastructure depends on Domain")

Pattern 2: Repository Pattern Validation

Goal: Verify repository abstractions

# Step 1: Find repositories
repositories = serena_find_symbol: "*Repository"

# Step 2: Check for interface
for repo in repositories:
    overview = serena_get_symbols_overview(repo)
    if "I" + repo.name not in overview:
        print(f"Warning: {repo.name} lacks interface")

# Step 3: Verify usage through abstraction
refs = serena_find_referencing_symbols: "OrderRepository"
for ref in refs:
    if ref.type == "OrderRepository" and not ref.is_interface:
        print(f"Warning: Direct repository usage at {ref.location}")

Pattern 3: Dependency Injection Validation

Goal: Verify proper DI registration

# Step 1: Find service registrations
registrations = serena_find_symbol: "Program/​ConfigureServices"

# Step 2: Check for interface-implementation pairs
services = [
    ("IOrderService", "OrderService"),
    ("IRepository", "Repository"),
]

for interface, impl in services:
    impl_refs = serena_find_referencing_symbols(impl)
    interface_refs = serena_find_referencing_symbols(interface)

    # Should reference interface, not implementation
    if len(impl_refs) > len(interface_refs):
        print(f"Warning: {impl} used directly instead of {interface}")

Code Smell Detection

Smell 1: God Class Detection

# Find classes with too many members
threshold = 20  # methods + properties

for file in project_files:
    overview = serena_get_symbols_overview(file)
    for type in overview.types:
        member_count = len(type.methods) + len(type.properties)
        if member_count > threshold:
            print(f"God Class: {type.name} has {member_count} members")

Smell 2: Feature Envy

# Method uses more features of other class than its own

for method in methods:
    own_type = method.parent_type
    other_refs = 0
    own_refs = 0

    for ref in method.references:
        if ref.symbol.parent == own_type:
            own_refs += 1
        else:
            other_refs += 1

    if other_refs > own_refs * 2:
        print(f"Feature Envy: {method.name} in {own_type}")

Smell 3: Circular Dependencies

# Build dependency graph
dependencies = {}

for type in all_types:
    refs = serena_find_referencing_symbols(type)
    dependencies[type] = refs

# Detect cycles
def find_cycles(graph, start, visited=None, path=None):
    if visited is None:
        visited = set()
    if path is None:
        path = []

    if start in path:
        cycle_start = path.index(start)
        return path[cycle_start:]

    if start in visited:
        return None

    visited.add(start)
    path.append(start)

    for neighbor in graph.get(start, []):
        cycle = find_cycles(graph, neighbor, visited, path)
        if cycle:
            return cycle

    path.pop()
    return None

# Check each type
for type in all_types:
    cycle = find_cycles(dependencies, type)
    if cycle:
        print(f"Circular dependency: {' -> '.join(cycle)}")

Smell 4: Shotgun Surgery

# Changes require modifications in many places

for type in all_types:
    change_impact = 0

    # Check how many places reference this type
    refs = serena_find_referencing_symbols(type)
    change_impact = len(refs)

    if change_impact > 10:
        print(f"Shotgun Surgery risk: {type} affects {change_impact} locations")

Dependency Analysis

Coupling Metrics

# Calculate coupling between modules

modules = {
    "Domain": "MyApp.Domain.*",
    "Application": "MyApp.Application.*",
    "Infrastructure": "MyApp.Infrastructure.*"
}

coupling_matrix = {}

for source_name, source_pattern in modules.items():
    coupling_matrix[source_name] = {}

    for target_name, target_pattern in modules.items():
        if source_name == target_name:
            continue

        # Count references from source to target
        count = 0
        source_types = serena_find_symbol(source_pattern)
        for type in source_types:
            refs = serena_find_referencing_symbols(type)
            for ref in refs:
                if target_pattern in ref:
                    count += 1

        coupling_matrix[source_name][target_name] = count

# Print coupling matrix
for source, targets in coupling_matrix.items():
    print(f"{source} depends on:")
    for target, count in targets.items():
        print(f"  {target}: {count} references")

Afferent/​Efferent Coupling

# Ca (Afferent Coupling) - who depends on me
ca = len(serena_find_referencing_symbols(type))

# Ce (Efferent Coupling) - who do I depend on
ce = 0
overview = serena_get_symbols_overview(type)
for ref in overview.references:
    ce += 1

# Instability = Ce / (Ca + Ce)
instability = ce / (ca + ce) if (ca + ce) > 0 else 0
print(f"Instability of {type}: {instability:.2f}")

Architecture Metrics

Lines of Code per Type

# Estimate complexity by symbol count

for file in project_files:
    overview = serena_get_symbols_overview(file)

    for type in overview.types:
        # Count lines (approximate)
        loc = len(type.methods) * 10  # avg 10 lines per method

        if loc > 500:
            print(f"Large type: {type.name} (~{loc} LOC)")

Inheritance Depth

# Find deep inheritance hierarchies

def get_inheritance_depth(type, depth=0):
    if not type.base_type:
        return depth
    return get_inheritance_depth(type.base_type, depth + 1)

for type in all_types:
    depth = get_inheritance_depth(type)
    if depth > 3:
        print(f"Deep hierarchy: {type.name} (depth {depth})")

Security Analysis

Hardcoded Secrets Detection

# Find string literals that look like secrets

for file in project_files:
    overview = serena_get_symbols_overview(file)

    for member in overview.members:
        if member.is_string_literal:
            value = member.value
            # Check for API keys, passwords, etc.
            patterns = [
                r"[a-zA-Z0-9]{32,}",  # API keys
                r"password\s*=\s*['\"]",  # Password assignments
                r"connection.*string",  # Connection strings
            ]
            for pattern in patterns:
                if re.search(pattern, value, re.IGNORECASE):
                    print(f"Potential secret: {file}:{member.line}")

SQL Injection Vulnerabilities

# Find string concatenation in SQL queries

sql_methods = serena_find_symbol("*Repository/​ExecuteSql")

for method in sql_methods:
    overview = serena_get_symbols_overview(method)

    # Check for string interpolation or concatenation
    if "string.Format" in overview or "$" in overview:
        refs = serena_find_referencing_symbols(method)
        print(f"SQL injection risk: {method} ({len(refs)} call sites)")

Performance Analysis

Async/​Await Patterns

# Find sync-over-async anti-patterns

async_methods = serena_find_symbol("*Async")

for method in async_methods:
    overview = serena_get_symbols_overview(method)

    # Check for .Result or .Wait()
    if ".Result" in overview or ".Wait()" in overview:
        print(f"Sync-over-async: {method}")

Allocation Hotspots

# Find methods likely to allocate heavily

for method in all_methods:
    overview = serena_get_symbols_overview(method)

    # LINQ, string manipulation in loops
    linq_count = overview.count_pattern("\.Select\(|\.Where\(|\.ToList\(")
    string_count = overview.count_pattern("\+\"|\$\"")

    if linq_count > 3 or string_count > 5:
        print(f"Allocation hotspot: {method}")

Integration with Other Skills

  • [skill:dotnet-serena-code-navigation] - Navigate before analyzing
  • [skill:dotnet-solid-principles] - Validate SOLID compliance
  • [skill:dotnet-security-owasp] - Security-focused analysis
  • [skill:dotnet-performance-patterns] - Performance analysis
  • [skill:dotnet-csharp-code-smells] - Code smell catalog

Analysis Report Template

## Code Analysis Report

### Executive Summary

- Total Types: X
- Total Methods: Y
- Critical Issues: Z
- Warnings: W

### Architecture Health

- Layer violations: N
- Circular dependencies: N
- Coupling violations: N

### Code Quality

- God classes: N
- High complexity: N
- Feature envy: N

### Recommendations

1. [Priority] Address circular dependencies in...
2. [Medium] Refactor God class...
3. [Low] Extract interface for...

### Detailed Findings

[See full report]

Best Practices

  1. Analyze regularly - Weekly architecture reviews
  2. Fix incrementally - Don't try to fix everything at once
  3. Track trends - Monitor metrics over time
  4. Focus on critical - Address high-impact issues first
  5. Document decisions - Why certain patterns were chosen

Quick Analysis Checklist

□ Check layer dependencies
□ Find circular references
□ Identify God classes
□ Validate DI registrations
□ Review public API surface
□ Check for code smells
□ Analyze test coverage
□ Review security hotspots