Smell — Architecture Bad Smell Detector
SkillDocs & knowledgeDetect software architecture bad smells, algorithmic complexity hotspots, and anti-patterns in a codebase. Produces a detailed markdown report identifying violations of architectural principles, design patterns, code quality, and performance complexity. Triggers on: smell, code smell, architecture smell, find anti-patterns, detect bad smells, complexity analysis, 代码坏味道, 架构坏味道, 反模式, 找出坏味道, 复杂度分析.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Smell — Architecture Bad Smell Detector skill
What this skill tells your AI
The instructions your AI receives, as published by smallnest/goal-workflow in skills/smell/SKILL.md and read by ahel’s review.
Analyze a codebase to find violations of software architecture principles, anti-patterns, code "bad smells," and algorithmic complexity hotspots. Produce a comprehensive, actionable markdown report.
Knowledge base: This skill encodes architectural patterns, anti-patterns, code smells, and algorithmic complexity heuristics drawn from industry research and practice, including the classic code smells catalog by Martin Fowler / Kent Beck (as organized on refactoring.guru: Bloaters, Object-Orientation Abusers, Change Preventers, Dispensables, Couplers).
The Job
- Understand the scope — ask what part of the project to analyze (full project, specific module, or recent changes)
- Scan the codebase using
find,grep, andAgent(Explore subagent) to gather candidate signals and evidence - Validate candidates against context, callers, history, workload, and measurements before confirming findings
- Generate a detailed markdown report saved to
tasks/smell-report-[timestamp].md - Present a summary of confirmed findings and separate candidates to the user
Step 1: Scope Clarification
Ask the user:
What scope should I analyze?
A. Entire project (thorough, may take time)
B. Specific module/directory: [please specify]
C. Only recently changed files (git diff)
D. Only architectural-level issues (skip low-level code smells)
If the user doesn't specify, default to option A for small projects (< 100 files) or C for large projects.
Step 2: Evidence Gathering
Use the Explore subagent (Agent with subagent_type: "Explore") to scan the codebase for architectural patterns and anti-patterns. Run multiple parallel explorations:
Exploration Commands
Run these in parallel to gather evidence efficiently:
- Project Structure Scan: Map the directory tree, identify the architectural style (layered, modular monolith, microservices, etc.)
- Dependency Analysis: Find import/include patterns, check for circular dependencies, identify coupling hotspots
- Module/Component Scan: Identify God Objects (files > 500 lines), check cohesion, check single responsibility violations
- Pattern Detection: Look for known anti-pattern signatures (static cling, service locator abuse, leaky abstractions)
- Testing Scan: Check test coverage patterns, test file locations, test-to-code ratios
- Naming & Clarity Scan: Flag misleading names, overly generic names (Manager, Helper, Util), inconsistent naming conventions
- Complexity Scan: Detect algorithmic complexity hotspots — nested loops, N+1 queries, repeated scans, sort-in-loop, expensive recomputation in render paths
Key Heuristics
Heuristics are candidate signals, not findings. A line-count, nesting, naming, or Big-O match must be validated against the code's responsibility, callers, change history, workload, and intentional constraints. Do not assign severity from a threshold alone.
| Category | Smell | Detection Heuristic |
|---|---|---|
| Architecture | Big Ball of Mud | No clear directory structure; everything in root or one flat folder; no separation of concerns |
| Architecture | Violated Layer Boundaries | Inner layers importing outer layers; infrastructure code in domain/core layer |
| Architecture | Missing Architecture | No src/, lib/, core/ separation; SQL inline with UI code; HTTP handlers mixed with business logic |
| Architecture | Distributed Monolith | Microservices sharing a database; services that can't deploy independently |
| Architecture | Anemic Domain Model | Model/entity classes with only getters/setters and no behavior; all logic in services |
| Architecture | CQRS Without Need | Separate read/write models for simple CRUD; unnecessary complexity |
| Architecture | Over-Layered Architecture | Excessive layers/tiers that add pass-through code with no real value |
| Architecture | Over-Abstraction | So many indirections/interfaces/generics that you get lost following the code |
| Architecture | Futuristic Architecture | Speculative flexibility for requirements that may never come (predicting the future) |
| Architecture | Technology-Enthusiast Architecture | Shiny/unproven tech adopted in production because it's new, not because it fits |
| Architecture | Overkill Architecture | Heavyweight architecture/tech thrown at a simple problem |
| Architecture | Cloud/Visio Architecture | Diagrams disconnected from the actual code and runtime reality |
| Coupling | Circular Dependencies | Module A imports B, B imports A; detected via import graph analysis |
| Coupling | Content Coupling | One module directly accesses another's internal/private members |
| Coupling | Common Coupling | Excessive global variables/shared mutable state; singleton abuse |
| Coupling | Stamp Coupling | Passing large data structures when only a few fields are needed |
| Cohesion | God Object | Single class/module > 500 lines; > 20 public methods; handles unrelated concerns |
| Cohesion | Shotgun Surgery | A single change requires touching 5+ files across unrelated modules |
| Cohesion | Feature Envy | Method calls foreign class methods more than its own class methods |
| Cohesion | Data Clumps | Same group of 3+ parameters appearing together in multiple method signatures |
| Design | Leaky Abstractions | Implementation details (DB queries, HTTP calls) exposed through interfaces |
| Design | Static Cling | Excessive use of static methods; static state that prevents testability |
| Design | Service Locator Abuse | DI container passed around instead of proper constructor injection |
| Design | Violated SOLID | SRP violations, OCP violations (switch/if-else chains on types), ISP violations (fat interfaces) |
| Design | Switch Statements | Same switch/if-else chain on a type code appearing in multiple places; should be polymorphism |
| Design | Refused Bequest | Subclass inherits methods/fields it doesn't use or overrides them to throw/no-op |
| Design | Alternative Classes w/ Different Interfaces | Two classes do the same thing but have differently-named methods |
| Design | Parallel Inheritance Hierarchies | Creating a subclass in one hierarchy forces a matching subclass in another |
| Design | Speculative Generality | Unused abstract classes, hooks, params, or generics "for future needs" (YAGNI) |
| Design | Incomplete Library Class | Wrapping/patching a third-party class because it lacks needed methods |
| Cohesion | Divergent Change | One module changed for many unrelated reasons (opposite of Shotgun Surgery) |
| Cohesion | Data Class | Class with only fields + getters/setters, no behavior (anemic data bag) |
| Cohesion | Lazy Class | Class/module that does too little to justify its existence |
| Coupling | Inappropriate Intimacy | Two classes access each other's private/internal parts too much |
| Coupling | Message Chains | Long call chains a.getB().getC().getD() (Law of Demeter violation) |
| Coupling | Middle Man | Class that only delegates every call to another class |
| Code | Temporary Field | Instance field set/used only in certain circumstances, empty otherwise |
| Code | Duplicated Code | Identical/similar logic appearing in 3+ places; copy-paste patterns |
| Code | Long Method | Methods > 50 lines; deep nesting (> 3 levels) |
| Code | Long Parameter List | Methods with > 4 parameters |
| Code | Primitive Obsession | Using strings/ints instead of domain types (e.g., string email instead of Email type) |
| Code | Magic Numbers/Strings | Hardcoded literals without named constants |
| Code | Comments as Deodorant | Excessive comments explaining bad code instead of refactoring |
| Code | Dead Code | Unused imports, unreachable code, commented-out blocks |
| Testing | No Tests | Modules with zero test coverage |
| Testing | Test-Implementation Coupling | Tests that assert internal implementation details instead of behavior |
| Testing | Slow Tests | Tests doing real I/O, database calls, network requests without mocking |
| Naming | Vague Names | Manager, Handler, Processor, Helper, Util, Service, Data, Info used excessively without context |
| Naming | Inconsistent Naming | Snake_case and camelCase mixed; different patterns for same concept |
| Readability | Deep Nesting (Arrow Anti-Pattern) | Loops/conditionals nested > 3 levels deep; rightward-drifting "arrow" shape hard to trace |
| Complexity | Nested Loops (O(n^2)+) | Loop inside loop; forEach inside for; map inside map; nested iteration suggesting polynomial complexity |
| Complexity | Repeated Linear Scan | includes()/indexOf()/.find() inside a loop; O(n*m) membership check on list instead of Set/Map |
| Complexity | Sort-in-Loop | .sort() or sorted() called inside iterative code; repeated O(n log n) when sort-once suffices |
| Complexity | N+1 Query Pattern | Database/API/HTTP call inside a loop; fetch/query/execute/findMany per iteration instead of batch |
| Complexity | Render-Path Recompute | .filter().map().sort() chains in component render body; expensive transforms without memoization |
| Complexity | Pairwise Comparison | Nested iteration comparing every element with every other; O(n^2) when sort+two-pointer would be O(n log n) |
| Complexity | Unnecessary Recompute | Same expensive computation repeated without caching; missing useMemo/memo/lazy eval |
| Complexity | Wrong Data Structure | Array used where Set/Map would give O(1) lookup; List where Queue/Heap/Stack is natural fit |
Step 3: Report Generation
Finding Identity and Evidence
Process every candidate in three stages:
- Candidate detection: static patterns, file metrics, and dependency scans produce candidates only.
- Context validation: read the implementation and relevant callers; check change frequency, input size, runtime frequency, framework constraints, generated/vendor status, and existing mitigations.
- Finding confirmation: merge candidates with the same root cause, affected path, failure/change scenario, and remediation direction into one finding.
Count findings by independent root cause, never by the number of principles they implicate. Use one Primary principle and optional Related principles. SOLID is an umbrella label; use SRP, OCP, or DIP as the primary label when the evidence supports a specific lens, without also creating a separate SOLID finding.
Canonical 11-Principle Matrix
| Principle | Confirming evidence | Common false positive / constraint |
|---|---|---|
| SOLID | A design problem spans multiple SOLID lenses or no narrower lens is reliable | Do not duplicate a specific SRP/OCP/DIP finding |
| DRY | The same business rule or knowledge must change in multiple places | Similar syntax that is expected to evolve independently |
| KISS | Extra layers, indirection, or machinery add cost without observable leverage | A small abstraction that removes real complexity |
| YAGNI | Unused extension points, parameters, adapters, or speculative requirements | A tested seam required by an existing boundary or change |
| SRP | Multiple independent reasons to change, supported by responsibilities or change history | File size or method count alone |
| Open/Closed (OCP) | Adding a known variant repeatedly modifies stable branching logic | One simple, local conditional |
| Dependency Inversion (DIP) | High-level policy directly depends on concrete infrastructure, harming replacement or testing | Adding an interface for a single stable implementation |
| Composition | Inheritance causes unwanted coupling, refused behavior, or inseparable variation axes | Replacing every valid inheritance relationship mechanically |
| Separation of Concerns | Business policy, I/O, presentation, or persistence concerns leak across boundaries | A deliberately thin boundary adapter |
| Fail Fast | Invalid input, state, or dependency propagates until a distant operation fails | Intentional aggregation, retry, or deferred validation semantics |
| Measure First | A performance, scale, or optimization claim lacks a baseline or representative workload | Static complexity reported as a measured bottleneck |
For each confirmed finding, record evidence strength (Measured, Observed, or Inferred) separately from confidence (High, Medium, or Low/Candidate). Evidence strength does not imply severity.
Severity Rubric
- Critical: correctness, reliability, security, data consistency, or measured system-level impact; normally requires high confidence.
- Warning: clear reach or repeated change/runtime cost with a concrete maintenance or runtime consequence.
- Suggestion: local, low-frequency, or limited-impact improvement with evidence.
- Candidate requiring measurement: static signal with unknown impact; exclude it from severity totals and put it in a separate report section.
Generate the report in this structure:
# Architecture Smell Report
**Project:** [project-name]
**Scope:** [scope description]
**Date:** [date]
**Analyzer:** smell skill (Ducc)
---
## Executive Summary
[2-3 paragraph summary of confirmed findings only: architectural style detected, overall health assessment, and top 3-5 critical issues. Mention candidates separately.]
---
## Architectural Style Detected
[Identify the architectural style: Layered, Modular Monolith, Microservices, Hexagonal, Clean Architecture, or Big Ball of Mud]
### Style Expectations vs. Reality
| Expectation | Reality | Status |
|-------------|---------|--------|
| [e.g., Clear layer separation] | [what was found] | ✅/⚠️/🔴 |
---
## Findings by Category
### 🔴 Critical Issues (Must Fix)
[Issues that fundamentally undermine architecture]
### 🟡 Warnings (Should Fix)
[Issues that degrade maintainability but don't block function]
### 🔵 Suggestions (Nice to Fix)
[Minor improvements that would increase quality]
### Candidates Requiring Measurement
[Static candidates whose runtime impact, change frequency, or workload is not yet established. These do not count toward severity totals.]
---
## Detailed Findings
### Finding #1: [Title]
- **Category:** [Architecture/Coupling/Cohesion/Design/Code/Testing/Naming/Complexity]
- **Severity:** 🔴 Critical / 🟡 Warning / 🔵 Suggestion
- **Anti-Pattern:** [Name of anti-pattern]
- **Location:** [file:line references and relevant callers]
- **Confidence:** [High/Medium]
- **Evidence strength:** [Measured/Observed/Inferred]
- **Failure or change scenario:** [Concrete scenario]
- **Primary principle:** [Most specific principle]
- **Related principles:** [Explanatory only; do not count separately]
- **Description:** [What was found and why it's a problem]
- **Evidence:** [Code, dependency, history, or measurement]
- **Measured/observed impact:** [Reach, frequency, consequence, or baseline]
- **Recommendation:** [Smallest justified refactoring]
- **Verification:** [How to prove behavior and impact]
---
## Dependency Graph Analysis
[Summary of module dependencies, circular dependencies found, coupling hotspots]
---
## Module Health Scorecard
| Module | Lines | God Object Risk | Coupling | Cohesion | Test Coverage | Health |
|--------|-------|----------------|----------|----------|---------------|--------|
| [name] | [N] | [Low/Med/High] | [Low/Med/High] | [Low/Med/High] | [% or N/A] | 🟢/🟡/🔴 |
---
## Smell Distribution
Count only deduplicated confirmed findings by their primary category. Related principles and candidates do not affect these totals.
| Category | Count | Critical | Warning | Suggestion |
|----------|-------|----------|---------|------------|
| Architecture | [N] | [N] | [N] | [N] |
| Coupling | [N] | [N] | [N] | [N] |
| Cohesion | [N] | [N] | [N] | [N] |
| Design | [N] | [N] | [N] | [N] |
| Code | [N] | [N] | [N] | [N] |
| Testing | [N] | [N] | [N] | [N] |
| Naming | [N] | [N] | [N] | [N] |
| Complexity | [N] | [N] | [N] | [N] |
---
## Refactoring Roadmap
Order work by impact, confidence, dependency sequence, and verification cost—not by principle count or smell name. Put only high-confidence, verifiable findings in Immediate Actions; for candidates, recommend the next measurement instead of a rewrite.
### Immediate Actions (This Sprint)
1. [Actionable fix 1]
2. [Actionable fix 2]
### Short-Term (1-3 Months)
1. [Structural improvement 1]
2. [Structural improvement 2]
### Long-Term (3-12 Months)
1. [Architectural transformation 1]
2. [Architectural transformation 2]
---
## Appendix: Anti-Pattern Reference
[A condensed reference of anti-patterns checked, with brief descriptions]
Step 4: Save and Present
Save the report to tasks/smell-report-[YYYY-MM-DD-HHmm].md and present a brief summary to the user.
Anti-Pattern Knowledge Base
This section documents the architectural anti-patterns and bad smells the skill knows about.
Architectural Anti-Patterns
Big Ball of Mud
The most common de-facto architecture. A haphazardly structured, sprawling system with no perceivable architecture. Characterized by:
- Promiscuous sharing of information between distant elements
- Global or duplicated important state
- Structure eroded beyond recognition or never defined
- Repeated expedient repair ("duct tape and bailing wire")
- Forces: Time pressure, cost, inexperience, complexity, change, scale
- Remedy: Define architecture boundaries, refactor incrementally, apply SHEARING LAYERS, KEEP IT WORKING
Distributed Monolith
Microservices that must be deployed together. Symptoms:
- Services share a database
- Synchronous chains of service calls
- Changes require coordinated deployments
- Remedy: Decouple data stores, introduce async messaging, enforce bounded contexts
Anemic Domain Model
Domain objects with only getters/setters (data bags), all logic in services. Violates:
- "Tell, Don't Ask" principle
- Rich Domain Model pattern from DDD
- Remedy: Move behavior into domain objects, use domain services only for cross-aggregate operations
God Object
A class that knows too much or does too much. Characteristics:
-
500 lines or > 20 public methods
- Handles unrelated concerns
- Difficult to test in isolation
- Single Responsibility Principle violation
- Remedy: Extract cohesive groups of methods into dedicated classes
Leaky Abstractions
Abstractions that expose implementation details. Signs:
- Interface methods named after implementation (e.g.,
SaveToPostgres,FetchFromRedis) - Consumers catching implementation-specific exceptions
- Configuration details exposed through abstractions
- Remedy: Design interfaces from the consumer's perspective, hide implementation details
Static Cling
Excessive use of static methods/state. Problems:
- Untestable (can't mock static calls)
- Hidden dependencies
- Thread-safety issues with static state
- Remedy: Use dependency injection, convert stateless statics to instance methods
Service Locator Abuse
Using a service locator instead of dependency injection. Issues:
- Hidden dependencies (dependencies not visible in constructor)
- Runtime errors instead of compile-time errors
- Testing difficulty
- Remedy: Use constructor injection, register dependencies at composition root
Violated Layer Boundaries (Clean/Onion/Hexagonal Architecture)
In layered architectures:
- Clean Architecture: Outer layers (frameworks) leaking into inner layers (use cases, entities)
- Onion Architecture: Infrastructure concerns in domain core
- Hexagonal Architecture: Business logic coupled to specific adapters instead of ports
- Remedy: Apply dependency inversion, define clear port interfaces
CQRS Overuse
Applying CQRS to simple CRUD. Signs:
- Separate read/write models for trivial data access
- Event sourcing when events don't add business value
- Unnecessary complexity
- Remedy: Use CQRS only when read/write models genuinely differ or have different scaling needs
Vertical Slice Contamination
In Vertical Slice Architecture:
- Cross-slice coupling (one feature directly calling another)
- Shared service classes undermining slice independence
- Remedy: Use events/messages for cross-slice communication, duplicate simple logic if needed
Top Ten Software Architecture Mistakes
A set of architecture-level anti-patterns describing over- and under-engineering. The common thread: architecture disconnected from real needs and reality. The opposite extreme (too little architecture) is equally a smell.
Over-Layered / Multitier Architecture
"Layers on layers on layers." Adding tiers beyond what the problem needs:
- Each layer just forwards calls to the next with no transformation or value
- Simple read requires touching 6+ classes across 4 layers
- Remedy: Collapse pass-through layers; keep only layers that carry real responsibility
Over-Abstraction
Abstraction piled on until the code is impossible to follow:
- Excessive interfaces, generics, factories, and indirection for single implementations
- You can't tell what actually runs without stepping through many hops
- Remedy: Inline single-implementation abstractions; abstract only at real variation points (rule of three)
Futuristic Architecture
Solution built for imagined future requirements that no one can actually predict:
- Extensibility points, plugin systems, config knobs nothing uses
- Most speculative flexibility is wasted effort — closely related to Speculative Generality and YAGNI
- Remedy: Build for today's known requirements; add flexibility when a real second case arrives
Technology-Enthusiast Architecture
New/shiny technology put into production because the architect liked it:
- Unproven tech adopted without validating it fits the problem or scales
- Chasing trends over stability
- Remedy: Evaluate tech against actual requirements; prefer proven tools; prototype before committing
Overkill Architecture
A simple problem solved with a disproportionate amount of architecture and technology:
- Microservices, event sourcing, k8s for a CRUD app with a handful of users
- Remedy: Match architecture weight to problem size (KISS); start simple, evolve when justified
Cloud / Visio Architecture
"Architecture" that exists only in nice diagrams, disconnected from the code and runtime reality:
- Diagrams don't match what's actually deployed; boxes and arrows with no code correspondence
- Remedy: Keep architecture docs grounded in and verified against the real system
Note on the opposite extreme: total lack of architecture (no boundaries, no structure) is equally a smell — see Big Ball of Mud and Missing Architecture. Both under- and over-engineering are failures.
Coupling & Cohesion Smells
Circular Dependencies
Module A → Module B → Module A. Detected via:
- Import graph analysis
- "Cannot access before initialization" errors
- Remedy: Extract shared interface/common module, apply dependency inversion
Content Coupling
One module directly modifying another's internal state. Signs:
- Direct field access across module boundaries
friend/package-private abuse- Remedy: Use public APIs, encapsulate internal state
Common Coupling (Global State)
Multiple modules depending on shared global mutable state:
- Global variables, singletons with mutable state
- Ambient context (e.g.,
CurrentUserstatic property) - Remedy: Parameterize, use dependency injection, make state explicit
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 277
- Forks
- 42
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
smell- Source
- github.com/smallnest/goal-workflow