237 lines
7.2 KiB
Plaintext
237 lines
7.2 KiB
Plaintext
|
|
---
|
||
|
|
description: Modular design principles and architecture guidelines for scalable development
|
||
|
|
globs:
|
||
|
|
alwaysApply: false
|
||
|
|
---
|
||
|
|
|
||
|
|
# Rule: Architecture and Modular Design
|
||
|
|
|
||
|
|
## Goal
|
||
|
|
Maintain a clean, modular architecture that scales effectively and prevents the complexity issues that arise in AI-assisted development.
|
||
|
|
|
||
|
|
## Core Architecture Principles
|
||
|
|
|
||
|
|
### 1. Modular Design
|
||
|
|
- **Single Responsibility**: Each module has one clear purpose
|
||
|
|
- **Loose Coupling**: Modules depend on interfaces, not implementations
|
||
|
|
- **High Cohesion**: Related functionality is grouped together
|
||
|
|
- **Clear Boundaries**: Module interfaces are well-defined and stable
|
||
|
|
|
||
|
|
### 2. Size Constraints
|
||
|
|
- **Files**: Maximum 250 lines per file
|
||
|
|
- **Functions**: Maximum 50 lines per function
|
||
|
|
- **Classes**: Maximum 300 lines per class
|
||
|
|
- **Modules**: Maximum 10 public functions/classes per module
|
||
|
|
|
||
|
|
### 3. Dependency Management
|
||
|
|
- **Layer Dependencies**: Higher layers depend on lower layers only
|
||
|
|
- **No Circular Dependencies**: Modules cannot depend on each other cyclically
|
||
|
|
- **Interface Segregation**: Depend on specific interfaces, not broad ones
|
||
|
|
- **Dependency Injection**: Pass dependencies rather than creating them internally
|
||
|
|
|
||
|
|
## Modular Architecture Patterns
|
||
|
|
|
||
|
|
### Layer Structure
|
||
|
|
```
|
||
|
|
src/
|
||
|
|
├── presentation/ # UI, API endpoints, CLI interfaces
|
||
|
|
├── application/ # Business logic, use cases, workflows
|
||
|
|
├── domain/ # Core business entities and rules
|
||
|
|
├── infrastructure/ # Database, external APIs, file systems
|
||
|
|
└── shared/ # Common utilities, constants, types
|
||
|
|
```
|
||
|
|
|
||
|
|
### Module Organization
|
||
|
|
```
|
||
|
|
module_name/
|
||
|
|
├── __init__.py # Public interface exports
|
||
|
|
├── core.py # Main module logic
|
||
|
|
├── types.py # Type definitions and interfaces
|
||
|
|
├── utils.py # Module-specific utilities
|
||
|
|
├── tests/ # Module tests
|
||
|
|
└── README.md # Module documentation
|
||
|
|
```
|
||
|
|
|
||
|
|
## Design Patterns for AI Development
|
||
|
|
|
||
|
|
### 1. Repository Pattern
|
||
|
|
Separate data access from business logic:
|
||
|
|
|
||
|
|
```python
|
||
|
|
# Domain interface
|
||
|
|
class UserRepository:
|
||
|
|
def get_by_id(self, user_id: str) -> User: ...
|
||
|
|
def save(self, user: User) -> None: ...
|
||
|
|
|
||
|
|
# Infrastructure implementation
|
||
|
|
class SqlUserRepository(UserRepository):
|
||
|
|
def get_by_id(self, user_id: str) -> User:
|
||
|
|
# Database-specific implementation
|
||
|
|
pass
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Service Pattern
|
||
|
|
Encapsulate business logic in focused services:
|
||
|
|
|
||
|
|
```python
|
||
|
|
class UserService:
|
||
|
|
def __init__(self, user_repo: UserRepository):
|
||
|
|
self._user_repo = user_repo
|
||
|
|
|
||
|
|
def create_user(self, data: UserData) -> User:
|
||
|
|
# Validation and business logic
|
||
|
|
# Single responsibility: user creation
|
||
|
|
pass
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Factory Pattern
|
||
|
|
Create complex objects with clear interfaces:
|
||
|
|
|
||
|
|
```python
|
||
|
|
class DatabaseFactory:
|
||
|
|
@staticmethod
|
||
|
|
def create_connection(config: DatabaseConfig) -> Connection:
|
||
|
|
# Handle different database types
|
||
|
|
# Encapsulate connection complexity
|
||
|
|
pass
|
||
|
|
```
|
||
|
|
|
||
|
|
## Architecture Decision Guidelines
|
||
|
|
|
||
|
|
### When to Create New Modules
|
||
|
|
Create a new module when:
|
||
|
|
- **Functionality** exceeds size constraints (250 lines)
|
||
|
|
- **Responsibility** is distinct from existing modules
|
||
|
|
- **Dependencies** would create circular references
|
||
|
|
- **Reusability** would benefit other parts of the system
|
||
|
|
- **Testing** requires isolated test environments
|
||
|
|
|
||
|
|
### When to Split Existing Modules
|
||
|
|
Split modules when:
|
||
|
|
- **File size** exceeds 250 lines
|
||
|
|
- **Multiple responsibilities** are evident
|
||
|
|
- **Testing** becomes difficult due to complexity
|
||
|
|
- **Dependencies** become too numerous
|
||
|
|
- **Change frequency** differs significantly between parts
|
||
|
|
|
||
|
|
### Module Interface Design
|
||
|
|
```python
|
||
|
|
# Good: Clear, focused interface
|
||
|
|
class PaymentProcessor:
|
||
|
|
def process_payment(self, amount: Money, method: PaymentMethod) -> PaymentResult:
|
||
|
|
"""Process a single payment transaction."""
|
||
|
|
pass
|
||
|
|
|
||
|
|
# Bad: Unfocused, kitchen-sink interface
|
||
|
|
class PaymentManager:
|
||
|
|
def process_payment(self, ...): pass
|
||
|
|
def validate_card(self, ...): pass
|
||
|
|
def send_receipt(self, ...): pass
|
||
|
|
def update_inventory(self, ...): pass # Wrong responsibility!
|
||
|
|
```
|
||
|
|
|
||
|
|
## Architecture Validation
|
||
|
|
|
||
|
|
### Architecture Review Checklist
|
||
|
|
- [ ] **Dependencies flow in one direction** (no cycles)
|
||
|
|
- [ ] **Layers are respected** (presentation doesn't call infrastructure directly)
|
||
|
|
- [ ] **Modules have single responsibility**
|
||
|
|
- [ ] **Interfaces are stable** and well-defined
|
||
|
|
- [ ] **Size constraints** are maintained
|
||
|
|
- [ ] **Testing** is straightforward for each module
|
||
|
|
|
||
|
|
### Red Flags
|
||
|
|
- **God Objects**: Classes/modules that do too many things
|
||
|
|
- **Circular Dependencies**: Modules that depend on each other
|
||
|
|
- **Deep Inheritance**: More than 3 levels of inheritance
|
||
|
|
- **Large Interfaces**: Interfaces with more than 7 methods
|
||
|
|
- **Tight Coupling**: Modules that know too much about each other's internals
|
||
|
|
|
||
|
|
## Refactoring Guidelines
|
||
|
|
|
||
|
|
### When to Refactor
|
||
|
|
- Module exceeds size constraints
|
||
|
|
- Code duplication across modules
|
||
|
|
- Difficult to test individual components
|
||
|
|
- New features require changing multiple unrelated modules
|
||
|
|
- Performance bottlenecks due to poor separation
|
||
|
|
|
||
|
|
### Refactoring Process
|
||
|
|
1. **Identify** the specific architectural problem
|
||
|
|
2. **Design** the target architecture
|
||
|
|
3. **Create tests** to verify current behavior
|
||
|
|
4. **Implement changes** incrementally
|
||
|
|
5. **Validate** that tests still pass
|
||
|
|
6. **Update documentation** to reflect changes
|
||
|
|
|
||
|
|
### Safe Refactoring Practices
|
||
|
|
- **One change at a time**: Don't mix refactoring with new features
|
||
|
|
- **Tests first**: Ensure comprehensive test coverage before refactoring
|
||
|
|
- **Incremental changes**: Small steps with verification at each stage
|
||
|
|
- **Backward compatibility**: Maintain existing interfaces during transition
|
||
|
|
- **Documentation updates**: Keep architecture documentation current
|
||
|
|
|
||
|
|
## Architecture Documentation
|
||
|
|
|
||
|
|
### Architecture Decision Records (ADRs)
|
||
|
|
Document significant decisions in `./docs/decisions/`:
|
||
|
|
|
||
|
|
```markdown
|
||
|
|
# ADR-003: Service Layer Architecture
|
||
|
|
|
||
|
|
## Status
|
||
|
|
Accepted
|
||
|
|
|
||
|
|
## Context
|
||
|
|
As the application grows, business logic is scattered across controllers and models.
|
||
|
|
|
||
|
|
## Decision
|
||
|
|
Implement a service layer to encapsulate business logic.
|
||
|
|
|
||
|
|
## Consequences
|
||
|
|
**Positive:**
|
||
|
|
- Clear separation of concerns
|
||
|
|
- Easier testing of business logic
|
||
|
|
- Better reusability across different interfaces
|
||
|
|
|
||
|
|
**Negative:**
|
||
|
|
- Additional abstraction layer
|
||
|
|
- More files to maintain
|
||
|
|
```
|
||
|
|
|
||
|
|
### Module Documentation Template
|
||
|
|
```markdown
|
||
|
|
# Module: [Name]
|
||
|
|
|
||
|
|
## Purpose
|
||
|
|
What this module does and why it exists.
|
||
|
|
|
||
|
|
## Dependencies
|
||
|
|
- **Imports from**: List of modules this depends on
|
||
|
|
- **Used by**: List of modules that depend on this one
|
||
|
|
- **External**: Third-party dependencies
|
||
|
|
|
||
|
|
## Public Interface
|
||
|
|
```python
|
||
|
|
# Key functions and classes exposed by this module
|
||
|
|
```
|
||
|
|
|
||
|
|
## Architecture Notes
|
||
|
|
- Design patterns used
|
||
|
|
- Important architectural decisions
|
||
|
|
- Known limitations or constraints
|
||
|
|
```
|
||
|
|
|
||
|
|
## Migration Strategies
|
||
|
|
|
||
|
|
### Legacy Code Integration
|
||
|
|
- **Strangler Fig Pattern**: Gradually replace old code with new modules
|
||
|
|
- **Adapter Pattern**: Create interfaces to integrate old and new code
|
||
|
|
- **Facade Pattern**: Simplify complex legacy interfaces
|
||
|
|
|
||
|
|
### Gradual Modernization
|
||
|
|
1. **Identify boundaries** in existing code
|
||
|
|
2. **Extract modules** one at a time
|
||
|
|
3. **Create interfaces** for each extracted module
|
||
|
|
4. **Test thoroughly** at each step
|
||
|
|
5. **Update documentation** continuously
|