architecture-review
SKILL.md
Architecture Review Skill
Analyze project structure at the macro level - packages, modules, layers, and boundaries.
When to Use
- User asks "review the architecture" / "check project structure"
- Evaluating package organization
- Checking dependency direction between layers
- Identifying architectural violations
- Assessing clean/hexagonal architecture compliance
Quick Reference: Architecture Smells
| Smell | Symptom | Impact |
|---|---|---|
| Package-by-layer bloat | service/ with 50+ classes |
Hard to find related code |
| Domain → Infra dependency | Entity imports @Repository |
Core logic tied to framework |
| Circular dependencies | A → B → C → A | Untestable, fragile |
| God package | util/ or common/ growing |
Dump for misplaced code |
| Leaky abstractions | Controller knows SQL | Layer boundaries violated |
Package Organization Strategies
Package-by-Layer (Traditional)
com.example.app/
├── controller/
│ ├── UserController.java
│ ├── OrderController.java
│ └── ProductController.java
├── service/
│ ├── UserService.java
│ ├── OrderService.java
│ └── ProductService.java
├── repository/
│ ├── UserRepository.java
│ ├── OrderRepository.java
│ └── ProductRepository.java
└── model/
├── User.java
├── Order.java
└── Product.java
Pros: Familiar, simple for small projects Cons: Scatters related code, doesn't scale, hard to extract modules
Package-by-Feature (Recommended)
com.example.app/
├── user/
│ ├── UserController.java
│ ├── UserService.java
│ ├── UserRepository.java
│ └── User.java
├── order/
│ ├── OrderController.java
│ ├── OrderService.java
│ ├── OrderRepository.java
│ └── Order.java
└── product/
├── ProductController.java
├── ProductService.java
├── ProductRepository.java
└── Product.java
Pros: Related code together, easy to extract, clear boundaries Cons: May need shared kernel for cross-cutting concerns
Hexagonal/Clean Architecture
com.example.app/
├── domain/ # Pure business logic (no framework imports)
│ ├── model/
│ │ └── User.java
│ ├── port/
│ │ ├── in/ # Use cases (driven)
│ │ │ └── CreateUserUseCase.java
│ │ └── out/ # Repositories (driving)
│ │ └── UserRepository.java
│ └── service/
│ └── UserDomainService.java
├── application/ # Use case implementations
│ └── CreateUserService.java
├── adapter/
│ ├── in/
│ │ └── web/
│ │ └── UserController.java
│ └── out/
│ └── persistence/
│ ├── UserJpaRepository.java
│ └── UserEntity.java
└── config/
└── BeanConfiguration.java
Key rule: Dependencies point inward (adapters → application → domain)
Dependency Direction Rules
The Golden Rule
┌─────────────────────────────────────────┐
│ Frameworks │ ← Outer (volatile)
├─────────────────────────────────────────┤
│ Adapters (Web, DB) │
├─────────────────────────────────────────┤
│ Application Services │
├─────────────────────────────────────────┤
│ Domain (Core Logic) │ ← Inner (stable)
└─────────────────────────────────────────┘
Dependencies MUST point inward only.
Inner layers MUST NOT know about outer layers.
Violations to Flag
// ❌ Domain depends on infrastructure
package com.example.domain.model;
import org.springframework.data.jpa.repository.JpaRepository; // Framework leak!
import javax.persistence.Entity; // JPA in domain!
@Entity
public class User {
// Domain polluted with persistence concerns
}
// ❌ Domain depends on adapter
package com.example.domain.service;
import com.example.adapter.out.persistence.UserJpaRepository; // Wrong direction!
// ✅ Domain defines port, adapter implements
package com.example.domain.port.out;
public interface UserRepository { // Pure interface, no JPA
User findById(UserId id);
void save(User user);
}
Architecture Review Checklist
1. Package Structure
- Clear organization strategy (by-layer, by-feature, or hexagonal)
- Consistent naming across modules
- No
util/orcommon/packages growing unbounded - Feature packages are cohesive (related code together)
2. Dependency Direction
- Domain has ZERO framework imports (Spring, JPA, Jackson)
- Adapters depend on domain, not vice versa
- No circular dependencies between packages
- Clear dependency hierarchy
3. Layer Boundaries
- Controllers don't contain business logic
- Services don't know about HTTP (no HttpServletRequest)
- Repositories don't leak into controllers
- DTOs at boundaries, domain objects inside
4. Module Boundaries
- Each module has clear public API
- Internal classes are package-private
- Cross-module communication through interfaces
- No "reaching across" modules for internals
5. Scalability Indicators
- Could extract a feature to separate service? (microservice-ready)
- Are boundaries enforced or just conventional?
- Does adding a feature require touching many packages?
Common Anti-Patterns
1. The Big Ball of Mud
src/main/java/com/example/
└── app/
├── User.java
├── UserController.java
├── UserService.java
├── UserRepository.java
├── Order.java
├── OrderController.java
├── ... (100+ files in one package)
Fix: Introduce package structure (start with by-feature)
2. The Util Dumping Ground
util/
├── StringUtils.java
├── DateUtils.java
├── ValidationUtils.java
├── SecurityUtils.java
├── EmailUtils.java # Should be in notification module
├── OrderCalculator.java # Should be in order domain
└── UserHelper.java # Should be in user domain
Fix: Move domain logic to appropriate modules, keep only truly generic utils
3. Anemic Domain Model
// Domain object is just data
public class Order {
private Long id;
private List<OrderLine> lines;
private BigDecimal total;
// Only getters/setters, no behavior
}
// All logic in "service"
public class OrderService {
public void addLine(Order order, Product product, int qty) { ... }
public void calculateTotal(Order order) { ... }
public void applyDiscount(Order order, Discount discount) { ... }
}
Fix: Move behavior to domain objects (rich domain model)
4. Framework Coupling in Domain
package com.example.domain;
@Entity // JPA
@Data // Lombok
@JsonIgnoreProperties(ignoreUnknown = true) // Jackson
public class User {
@Id @GeneratedValue
private Long id;
@NotBlank // Validation
private String email;
}
Fix: Separate domain model from persistence/API models
Analysis Commands
When reviewing architecture, examine:
# Package structure overview
find src/main/java -type d | head -30
# Largest packages (potential god packages)
find src/main/java -name "*.java" | xargs dirname | sort | uniq -c | sort -rn | head -10
# Check for framework imports in domain
grep -r "import org.springframework" src/main/java/*/domain/ 2>/dev/null
grep -r "import javax.persistence" src/main/java/*/domain/ 2>/dev/null
# Find circular dependencies (look for bidirectional imports)
# Check if package A imports from B and B imports from A
Recommendations Format
When reporting findings:
## Architecture Review: [Project Name]
### Structure Assessment
- **Organization**: Package-by-layer / Package-by-feature / Hexagonal
- **Clarity**: Clear / Mixed / Unclear
### Findings
| Severity | Issue | Location | Recommendation |
|----------|-------|----------|----------------|
| High | Domain imports Spring | `domain/model/User.java` | Extract pure domain model |
| Medium | God package | `util/` (23 classes) | Distribute to feature modules |
| Low | Inconsistent naming | `service/` vs `services/` | Standardize to `service/` |
### Dependency Analysis
[Describe dependency flow, violations found]
### Recommendations
1. [Highest priority fix]
2. [Second priority]
3. [Nice to have]
Token Optimization
For large codebases:
- Start with
findto understand structure - Check only domain package for framework imports
- Sample 2-3 features for pattern analysis
- Don't read every file - look for patterns
Weekly Installs
15
Repository
decebals/claude…ode-javaGitHub Stars
387
First Seen
Feb 19, 2026
Security Audits
Installed on
github-copilot15
opencode14
gemini-cli14
amp14
codex14
kimi-cli14