ab-socks-refactor
Protocol and playbook for refactoring bloated controllers, tangled views, and paying down technical debt in the AB-Socks project. Use this skill whenever refactoring a file, breaking down a controller
SKILL.md.claude/skills/ab-socks-refactor/SKILL.md
GitHubAB-Socks Code Quality & Refactoring Playbook
This skill provides step-by-step guidance for safely decomposing bloated files, extracting domain services, and keeping the codebase maintainable and extensible.
1. Architectural Guardrails & Thresholds
| Component | Target Size | Hard Limit | Rules |
|---|---|---|---|
Controller (app/controllers/) |
< 80 lines | 120 lines | Zero SQL queries, zero calculation logic. Only parses $_GET/$_POST, calls a service, passes variables to renderView(). |
View (views/) |
Modular | N/A | Zero database queries (db()), zero form handling ($_POST). Only loops, conditions, and e() escaping. |
Service (app/services/) |
Focused | N/A | All SQL queries, business logic, calculations, and validations live here as plain global functions returning ['ok' => bool, 'error' => string]. |
Core Helper (app/core/) |
Domain-agnostic | N/A | Formatting, slug generation, general helpers. No direct order/product business logic. |
2. Refactoring Protocol (Step-by-Step)
When refactoring a legacy or bloated controller (e.g. appearance.php, product_edit.php, settings.php):
Step 1: Establish Baseline
Run the verifier to see current errors/warnings:
php tools/verify.php
Step 2: Identify Concerns
Break the controller down into 3 distinct parts:
- Input handling & state: What does it read from
$_GET,$_POST, or$_SESSION? - Business logic & DB writes: What validation, SQL queries, or data transformations are happening?
- View payload: What variables are actually passed into
renderView()?
Step 3: Extract Domain Service Function
Move all DB queries, validation, and calculations into the appropriate service in app/services/ (or create a new service if a new domain concern).
Service Function Contract:
/**
* Saves or updates an entity from form input.
*
* @param array $input Raw form data (sanitized inside service)
* @param int $id Record ID (0 for new)
* @return array ['ok' => bool, 'error' => string|null, 'id' => int|null]
*/
function saveEntityFromRequest(array $input, int $id = 0): array {
verifyCsrf();
// 1. Validate
$errors = validateEntityInput($input);
if (!empty($errors)) {
return ['ok' => false, 'error' => implode(' ', $errors)];
}
// 2. Perform DB operations with prepared statements
$db = db();
// Use transaction if touching stock, money, or multiple tables!
// ...
return ['ok' => true, 'id' => $id ?: (int) $db->lastInsertId()];
}
Step 4: Streamline the Controller
The controller should now be a clean orchestrator (typically 30–60 lines):
<?php
$id = (int) ($_GET['id'] ?? 0);
$entity = $id ? getEntityById($id) : null;
if ($id && !$entity) redirect('admin/entities.php');
$error = null;
$success = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$result = saveEntityFromRequest($_POST, $id);
if ($result['ok']) {
setFlash('success', 'تغییرات با موفقیت ذخیره شد.');
redirect('admin/entities.php');
} else {
$error = $result['error'];
}
}
$pageTitle = $id ? 'ویرایش آیتم' : 'افزودن آیتم';
renderView('admin/entity_edit', compact('pageTitle', 'entity', 'error', 'success'));
Step 5: Decompose Heavy Views into Partials
If a view has grown past 200–300 lines or contains repetitive UI (like cards, tabs, form sections):
- Extract subsections into
views/admin/partials/orviews/site/partials/. - Include them via standard PHP:
<?php require __DIR__ . '/partials/entity_tab_general.php'; ?> - Ensure no partial performs database queries or mutates state.
Step 6: Eliminate Inline Scripts & Deduplicate Front-End Logic
- Never write new duplicate JS helpers: Check
docs/COMPONENTS.mdfor existing toast, modal, formatter, autocomplete, and image compression tools. - Eliminate inline
<script>: Move interactive behaviors to declarativedata-ab-*attributes or dedicated external JS files. Keep inline scripts under 20 lines. - Use unified design tokens: Never declare page-specific
:rootpalettes or raw hex colors in component CSS.
3. Safe Refactoring Checklist
-
php tools/verify.phppasses with 0 errors and adheres to the ratchet baseline. - No controller exceeds 120 lines (aim for < 80).
- No SQL queries exist in any touched view.
- No DB writes exist directly in any touched controller.
- Zero duplicate JS helpers introduced (consult
docs/COMPONENTS.md). - No inline
<script>tags exceed 20 lines in touched views. - CSS uses unified
:rootvariables without redundant palette declarations. - Transaction and row locking (
FOR UPDATE) preserved if money/stock is involved. - CSRF verification retained on all POST operations.
- Persian UI text and English comments preserved.