Files
ForgeLM/.agents/rules/code-organization-principles.md

115 lines
3.7 KiB
Markdown

---
trigger: always_on
---
## Code Organization Principles
- Generate small, focused functions with clear single purposes (typically 10-50 lines)
- Keep cognitive complexity low (cyclomatic complexity < 10 for most functions)
- Maintain clear boundaries between different layers (presentation, business logic, data access)
- Design for testability from the start, avoiding tight coupling that prevents testing
- Apply consistent naming conventions that reveal intent without requiring comments
### Module Boundaries
**Problem:** Cross-module coupling makes changes ripple across codebase.
**Solution:** Feature-based organization with clear public interfaces:
- One feature = one directory
- Each module exposes a public API (exported functions/classes)
- Internal implementation details are private
- Cross-module calls only through public API
**Directory Structure (Language-Agnostic):**
> Paths below are illustrative examples following `project-structure.md` — the single source of truth for project layout.
> **Note:** The generic filenames below are illustrative. Always use language-specific naming conventions from the relevant `project-structure-*` file (e.g., `storage.go` in Go, `task.api.ts` in TypeScript, `task_repository.dart` in Dart).
```
/task
- public_api.{ext} # Exported interface
- business.{ext} # Pure logic
- store.{ext} # I/O abstraction (interface)
- postgres.{ext} # I/O implementation
- mock.{ext} # Test implementation
- test.{ext} # Unit tests (mocked I/O)
- integration.test.{ext} # Integration tests (real I/O)
```
**Go Example:**
```
apps/backend/internal/features/task/
- service.go # Public API of this feature (Service struct)
- handler.go # HTTP handlers
- logic.go # Pure domain logic
- storage.go # interface Storage
- storage_pg.go # implements Storage (PostgreSQL)
- storage_mock.go # Mock implementation for testing
- logic_test.go # Unit tests with MockStorage
- postgres_integration_test.go # Integration test with Testcontainers
```
**Vue Example:**
```
/apps/frontend/src/features/task
- index.ts # Public exports
- task.service.ts # Business logic
- task.api.ts # interface TaskAPI
- task.api.backend.ts # implements TaskAPI
- task.store.ts # Pinia store (uses TaskAPI)
- task.service.spec.ts # Unit tests (mock API)
```
### Feature Interaction Patterns
**Direct Import**
When a feature needs another feature's capabilities, import its Service directly:
```go
// In features/order/logic.go
import "yourapp/internal/features/task"
type Logic struct {
taskService *task.Service // Direct dependency injection
}
func (l *Logic) CreateOrder(ctx context.Context, req CreateOrderRequest) error {
// Use task service directly
task, err := l.taskService.GetTask(ctx, req.TaskID)
// ... rest of logic
}
```
**Rules**
- Only import Service (public API), never internal files like logic.go or storage.go
- Declare dependency in the dependent feature's Service constructor
- Wire dependencies in cmd/api/main.go
**Wiring Example**
```go
// cmd/api/main.go
taskService := task.NewService(taskStorage)
orderService := order.NewService(orderStorage, taskService) // Pass task service
```
### Avoid Circular Dependencies
**Problem:** Module A imports B, B imports A
- Causes build failures, initialization issues
- Indicates poor module boundaries
**Solution:**
- Extract shared code to third module
- Restructure dependencies (A→C, B→C)
- Use dependency injection
### Related Principles
- Core Design Principles @core-design-principles.md
- Project Structure @project-structure.md
- Architectural Patterns — Testability-First Design @architectural-pattern.md