# Modular Code Rules CRITICAL: Never write giant monolithic files. Split code into modules, libraries, and microservice-ready components. ## Problem Agents write enormous single files that are hard to review, test, debug, and maintain. No clear boundaries between features. ## Core Principles 1. **Maximum file size**: 100 lines per file (excluding tests and migrations) 2. **Maximum function/method size**: 30 lines 3. **Maximum class size**: 5 public methods 4. **One responsibility per file**: A file does ONE thing ## Module Structure (Mandatory) Every feature must be organized as an independent module: ``` {feature}/ ├── Controllers/ # HTTP request handling (thin) ├── Services/ # Business logic (fat) ├── Repositories/ # Data access (abstracted) ├── Models/ # Data definitions ├── Routes/ # Route definitions ├── Events/ # Events this module emits ├── Listeners/ # Events this module handles ├── Jobs/ # Async work this module performs ├── Requests/ # Input validation (not in controller) ├── Resources/ # Output transformation (not raw model) ├── Exceptions/ # Module-specific exceptions ├── Tests/ # Module-specific tests └── ModuleServiceProvider.php # Module registration ``` ## Service Layer Rules ```php // ❌ BAD: Business logic in controller class ProductController { public function store(Request $request) { $product = Product::create($request->all()); Cache::forget('products'); event(new ProductCreated($product)); Mail::to($product->vendor)->send(new NewProduct($product)); return response()->json($product); } } // ✅ GOOD: Business logic in service class ProductController { public function __construct(private ProductService $service) {} public function store(ProductStoreRequest $request): JsonResponse { $product = $this->service->create($request->validated()); return response()->json(new ProductResource($product), 201); } } class ProductService { public function create(array $data): Product { $product = $this->repository->create($data); $this->clearCache(); ProductCreated::dispatch($product); $this->notifyVendor($product); return $product; } } ``` ## Repository Pattern (Mandatory for Data Access) ```php // ❌ BAD: Query in controller or service $products = Product::where('active', true)->paginate(20); // ✅ GOOD: Query in repository interface ProductRepositoryInterface { public function listActive(int $perPage = 20): LengthAwarePaginator; } class ProductRepository implements ProductRepositoryInterface { public function __construct(private Product $model) {} public function listActive(int $perPage = 20): LengthAwarePaginator { return $this->model->query() ->where('is_active', true) ->orderBy('created_at', 'desc') ->paginate($perPage); } } ``` ## Cross-Module Communication Modules MUST NOT import models or repositories from other modules. ``` ❌ Product module imports Order model directly ❌ Order module calls ProductRepository directly ✅ Product module dispatches ProductCreated event ✅ Order module listens to ProductCreated event ✅ Module boundaries enforced via interfaces ``` ## Microservice Readiness Every module must be extractable as an independent service: 1. **Own database migrations**: Module manages its own tables 2. **Own routes**: Module registers its own routes 3. **Own config**: Module has its own configuration 4. **Own tests**: Module tests run independently 5. **Interface contracts**: Module exposes interfaces, not implementations ## File Splitting Rules When a file exceeds 100 lines: ``` Original: ProductController.php (250 lines) ↓ Split into: ProductController.php # index, show (thin delegates) ProductStoreController.php # store endpoint (thin delegates) ProductUpdateController.php # update endpoint (thin delegates) ProductService.php # business logic (called by all) ``` When a service exceeds 5 methods: ``` Original: ProductService.php (8 methods) ↓ Split into: ProductCrudService.php # create, update, delete ProductSearchService.php # list, search, filter ProductPricingService.php # calculatePrice, applyDiscount ``` ## Language-Specific Module Patterns ### Node.js ``` src/modules/product/ ├── routes.js ├── controller.js ├── service.js ├── repository.js ├── model.js ├── validators.js └── __tests__/ ``` ### Go ``` internal/product/ ├── handler.go ├── service.go ├── repository.go ├── model.go └── handler_test.go ``` ### Flutter/Dart ``` lib/features/product/ ├── data/ │ ├── repositories/ │ └── models/ ├── domain/ │ ├── entities/ │ └── usecases/ └── presentation/ ├── pages/ ├── widgets/ └── providers/ ``` ## Checklist - [ ] Every file under 100 lines - [ ] Every function under 30 lines - [ ] Every class under 5 public methods - [ ] Features organized as modules - [ ] Service layer contains business logic - [ ] Repository layer abstracts data access - [ ] Controllers are thin (5-10 lines per method) - [ ] Cross-module communication via events - [ ] Each module testable independently - [ ] Each module extractable to microservice