| name | arch-check |
| description | Verify architecture health including layer violations, circular dependencies, package structure, and design pattern compliance |
Architecture Check Skill
Verify the codebase adheres to architectural principles, layer boundaries, and design patterns.
Instructions
1. Verify Layer Architecture
This project follows a layered architecture:
┌─────────────────────────────────────────┐
│ Controller Layer │ ← HTTP endpoints
├─────────────────────────────────────────┤
│ Service Layer │ ← Business logic
├─────────────────────────────────────────┤
│ Provider / Strategy / Mapper Layer │ ← Data access, transformations
├─────────────────────────────────────────┤
│ Model Layer │ ← Domain objects (records)
└─────────────────────────────────────────┘
Allowed Dependencies:
- Controller → Service → Provider/Strategy/Mapper → Model
- All layers → Model (models are shared)
- Service → Service (peer services)
Violations to detect:
import ...service.strategy.FetchCurrentConditionsStrategy;
import ...controller.SpotsController;
import ...service.AggregatorService;
Use Grep to check imports in each layer:
grep -r "import.*strategy" src/main/java/**/controller/
grep -r "import.*controller\|import.*service[^/]" src/main/java/**/provider/
grep -r "import.*service\|import.*controller\|import.*provider" src/main/java/**/model/
2. Detect Circular Dependencies
Check for circular imports between packages:
Package dependency graph:
controller → service → provider
→ strategy
→ mapper
→ model (allowed from all)
Search patterns:
Common circular dependency patterns:
- Service A calls Service B, Service B calls Service A
- Listener/callback creating cycles
- Utility classes depending on domain classes
3. Package Structure Compliance
Verify expected package structure:
src/main/java/com/github/pwittchen/varun/
├── Application.java # Main entry point
├── config/ # Configuration classes
│ └── *Config.java
├── controller/ # REST controllers
│ └── *Controller.java
├── exception/ # Custom exceptions
│ └── *Exception.java
├── mapper/ # Data mappers
│ └── *Mapper.java
├── model/ # Domain models (records)
│ └── *.java
├── provider/ # Data providers
│ └── *Provider.java
└── service/ # Business services
├── *Service.java
└── strategy/ # Strategy implementations
└── *Strategy*.java
Check for:
- Files in wrong packages (e.g., Service in controller package)
- Missing package conventions (e.g., Helper in service package)
- Inconsistent naming (e.g.,
FooManager instead of FooService)
4. Design Pattern Compliance
Strategy Pattern (CurrentConditions)
interface FetchCurrentConditionsStrategy {
boolean canProcess(int windguruId);
CurrentConditions fetch();
}
Provider Pattern (Data Loading)
Caching Pattern
5. Dependency Injection Compliance
Check for:
private ForecastService service = new ForecastService();
private final ForecastService service;
public MyService(ForecastService service) {
this.service = service;
}
@Autowired
private ForecastService service;
@RequiredArgsConstructor
public class MyService {
private final ForecastService forecastService;
}
Search for anti-patterns:
grep -r "@Autowired" src/main/java/
grep -r "new.*Service\(\)" src/main/java/
6. Single Responsibility Check
Analyze classes for responsibility violations:
Warning signs:
- Class > 500 lines (potential god class)
- More than 10 public methods
- More than 7 dependencies injected
- Mixed concerns (HTTP + business logic + data access)
Check service classes:
class BigService {
void handleRequest()
void processData()
void saveToCache()
void sendNotification()
void formatResponse()
}
7. API Design Consistency
Controller conventions:
@RestController
@RequestMapping("/api/v1/...")
public class XxxController {
@GetMapping("/{id}")
public Mono<Xxx> getById(@PathVariable int id)
@PostMapping
public Mono<Xxx> create(@RequestBody XxxRequest request)
}
Check for:
- Mixed response types (some Mono, some blocking)
- Inconsistent URL patterns
- Missing @PathVariable/@RequestParam annotations
- Business logic in controllers
8. Configuration Separation
Check configuration is externalized:
private static final String API_URL = "https://api.example.com";
private static final int TIMEOUT = 5000;
@Value("${api.url}")
private String apiUrl;
@ConfigurationProperties(prefix = "api")
public class ApiConfig {
private String url;
private int timeout;
}
Search for hardcoded values:
grep -r "http://" src/main/java/
grep -r "https://" src/main/java/
grep -rE "[0-9]{4,}" src/main/java/
9. Exception Handling Architecture
Check exception flow:
Controller → Service → Provider/Strategy
↑ ↑ ↑
└───────────┴───────────┴── Exceptions bubble up
Controller: Translates to HTTP responses
Service: May wrap in domain exceptions
Provider: Throws low-level exceptions
Verify:
- Custom exceptions extend appropriate base
- Exceptions have meaningful messages
- No swallowed exceptions (empty catch blocks)
- Consistent error response format
10. Test Architecture
Check test structure mirrors main:
src/test/java/
├── controller/ # Controller tests (WebTestClient)
├── service/ # Service unit tests
├── provider/ # Provider tests
├── strategy/ # Strategy tests
└── integration/ # Integration tests
src/e2e/java/ # End-to-end tests (Playwright)
Verify:
- Tests exist for each layer
- Proper mocking (mock dependencies, not internals)
- No test interdependencies
Output Format
## Architecture Health Report
### Summary
| Check | Status | Issues |
|-------|--------|--------|
| Layer Violations | ✓/✗ | X |
| Circular Dependencies | ✓/✗ | X |
| Package Structure | ✓/✗ | X |
| Design Patterns | ✓/✗ | X |
| DI Compliance | ✓/✗ | X |
| Single Responsibility | ✓/✗ | X |
| API Consistency | ✓/✗ | X |
### Layer Violations
#### [Violation Description]
**File**: `path/to/file.java:line`
**Issue**: Controller directly imports Strategy
**Impact**: Bypasses service layer, harder to test
**Fix**: Inject service that uses strategy
### Circular Dependencies
ServiceA ←→ ServiceB (CIRCULAR)
**Fix**: Extract shared logic to new service, or use events
### Package Structure Issues
| File | Current Package | Expected Package |
|------|-----------------|------------------|
| FooHelper.java | service | util or helper |
### Design Pattern Violations
#### Strategy Pattern
- Missing: `XxxStrategy` not implementing interface
- Orphaned: `YyyStrategy` not registered
### Dependency Injection Issues
| File | Line | Issue | Fix |
|------|------|-------|-----|
| Service.java | 15 | Field injection | Use constructor |
| Handler.java | 23 | Direct instantiation | Inject dependency |
### Single Responsibility Concerns
| Class | Lines | Methods | Dependencies | Concern |
|-------|-------|---------|--------------|---------|
| BigService | 650 | 15 | 9 | Consider splitting |
### Hardcoded Values Found
| File | Line | Value | Recommendation |
|------|------|-------|----------------|
| Client.java | 42 | "https://..." | Move to config |
### Architecture Diagram (Current)
┌─────────────┐ ┌─────────────┐
│ Controller │────▶│ Service │
└─────────────┘ └──────┬──────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│Provider │ │Strategy │ │ Mapper │
└─────────┘ └─────────┘ └─────────┘
### Recommendations
1. **Critical**: Fix circular dependency between X and Y
2. **High**: Refactor BigService into smaller services
3. **Medium**: Move hardcoded URLs to configuration
4. **Low**: Rename FooManager to FooService for consistency
Execution Steps
- Use
Glob to list all Java files by package
- Use
Grep to check imports in each layer
- Read large files to check responsibilities
- Verify design pattern implementations
- Check for DI anti-patterns
- Analyze configuration usage
- Generate architecture health report
Notes
- This project intentionally has no database layer (in-memory caching)
- Reactive types (Mono/Flux) should be consistent across layers
- Strategy pattern is used for weather station integrations
- Configuration is split between application.yml and code constants
- Some "violations" may be intentional trade-offs - use judgment