From zenbu-powers
PHP IT Stage 4:重構階段。在測試保護下,小步驟改善程式碼品質。 兩階段工作流:Phase A 重構測試程式碼 → 跑測試 → Phase B 重構生產程式碼 → 跑測試。 嚴格遵守 /aibdd.auto.php.it.code-quality 規範。 可被 /aibdd.auto.php.it.control-flow 調用,也可獨立使用。
npx claudepluginhub zenbuapps/zenbu-powers --plugin zenbu-powersThis skill uses the workspace's default tool permissions.
本 skill 為 AI-BDD 4 階段流程中的 **Stage 4 重構協調者**:
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Guides code writing, review, and refactoring with Karpathy-inspired rules to avoid overcomplication, ensure simplicity, surgical changes, and verifiable success criteria.
Share bugs, ideas, or general feedback.
本 skill 為 AI-BDD 4 階段流程中的 Stage 4 重構協調者:
Stage 1: test-skeleton
Stage 2: red
Stage 3: green
Stage 4: refactor ← 本 skill
在全綠燈保護下,以小步驟、連續測試的方式改善程式碼品質。
嚴格遵守 /zenbu-powers:aibdd.auto.php.it.code-quality 規範(透過 skill 載入)。
重構啟動前必須確認:
/zenbu-powers:aibdd.auto.php.it.code-quality 規範若有紅燈 → 拒絕執行,提示先回到 Stage 3 修復。
┌─────────────────────────────────┐
│ 執行測試(確認全綠) │
└──────────────┬──────────────────┘
↓
┌─────────────────────────────────┐
│ 【Phase A】重構測試程式碼 │
│ tests/integration/ │
│ - 刪除 TODO 註解 │
│ - 刪除 [Handler: xxx] 標註 │
│ - 改善變數命名 │
│ - 簡化重複邏輯 │
└──────────────┬──────────────────┘
↓
┌─────────────────────────────────┐
│ 執行測試(仍全綠) │
└──────────────┬──────────────────┘
↓
┌─────────────────────────────────┐
│ 【Phase B】重構生產程式碼 │
│ src/ │
│ - 套用 SOLID │
│ - Early Return │
│ - 抽取常數 │
│ - 改善命名 / 型別宣告 │
└──────────────┬──────────────────┘
↓
┌─────────────────────────────────┐
│ 執行測試(仍全綠) │
└──────────────┬──────────────────┘
↓
完成
階段順序不可顛倒! Why:必須先清除測試中的 Handler 標註與 TODO,使測試成為純粹的業務意圖表達; 之後重構產品程式碼時,才能以「清楚的業務語意」作為重構方向的依據。
tests/integration/**/*.php
// TODO: 註解// [Handler: xxx] 參考 /zenbu-powers:aibdd.auto.php.it.handlers.xxx 標註// Given / // When / // Then 業務語意註解Before
public function test_成功增加影片進度(): void
{
// Given 用戶 "Alice" 在課程 1 的進度為 50%
// [Handler: aggregate-given] 參考 /zenbu-powers:aibdd.auto.php.it.handlers.aggregate-given
// TODO: 實作測試程式碼
$u = $this->factory()->user->create(['display_name' => 'Alice']);
$this->ids['Alice'] = $u;
$p = new LessonProgress($u, 1, 50, 'in_progress');
$this->repos->lessonProgress->save($p);
// When 用戶 "Alice" 更新課程 1 的影片進度為 80%
// [Handler: command] 參考 /zenbu-powers:aibdd.auto.php.it.handlers.command
try {
$this->services->lesson->updateVideoProgress($u, 1, 80);
} catch (\Throwable $e) {
$this->lastError = $e;
}
// Then 操作成功
// [Handler: success-failure] 參考 /zenbu-powers:aibdd.auto.php.it.handlers.success-failure
$this->assert_operation_succeeded();
// And 用戶 "Alice" 在課程 1 的進度應為 80%
// [Handler: aggregate-then] 參考 /zenbu-powers:aibdd.auto.php.it.handlers.aggregate-then
$r = $this->repos->lessonProgress->find($u, 1);
$this->assertSame(80, $r->getProgress());
}
After
public function test_成功增加影片進度(): void
{
// Given 用戶 "Alice" 在課程 1 的進度為 50%
$userId = $this->factory()->user->create(['display_name' => 'Alice']);
$this->ids['Alice'] = $userId;
$initialProgress = new LessonProgress($userId, 1, 50, 'in_progress');
$this->repos->lessonProgress->save($initialProgress);
// When 用戶 "Alice" 更新課程 1 的影片進度為 80%
try {
$this->services->lesson->updateVideoProgress($userId, 1, 80);
} catch (\Throwable $e) {
$this->lastError = $e;
}
// Then 操作成功
$this->assert_operation_succeeded();
// And 用戶 "Alice" 在課程 1 的進度應為 80%
$updated = $this->repos->lessonProgress->find($userId, 1);
$this->assertSame(80, $updated->getProgress());
}
// TODO: 殘留// [Handler: 標註殘留// Given/When/Then 業務註解完整保留src/Models/
src/Repositories/
src/Services/
src/Exceptions/
private constdeclare(strict_types=1);?Type 明確化$wpdb 呼叫使用 prepare()詳細規範請載入
/zenbu-powers:aibdd.auto.php.it.code-quality。
Before
<?php
class LessonService
{
private $repo;
public function __construct($repo)
{
$this->repo = $repo;
}
public function updateVideoProgress($userId, $lessonId, $progress)
{
$existing = $this->repo->find($userId, $lessonId);
if ($existing) {
if ($progress <= $existing->getProgress()) {
throw new \Exception("進度不可倒退");
}
}
if ($progress < 0 || $progress > 100) {
throw new \Exception("進度超出範圍");
}
$p = new LessonProgress($userId, $lessonId, $progress,
$progress >= 100 ? 'completed' : 'in_progress');
$this->repo->save($p);
}
}
After
<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\LessonProgress;
use App\Repositories\LessonProgressRepositoryInterface;
use App\Exceptions\InvalidStateException;
class LessonService
{
private const PROGRESS_MIN = 0;
private const PROGRESS_MAX = 100;
private const COMPLETION_THRESHOLD = 100;
public function __construct(
private LessonProgressRepositoryInterface $progressRepo,
) {}
public function updateVideoProgress(int $userId, int $lessonId, int $progress): void
{
$this->assertProgressInRange($progress);
$existing = $this->progressRepo->findByUserAndLesson($userId, $lessonId);
if ($existing !== null && $progress <= $existing->getProgress()) {
throw new InvalidStateException('進度不可倒退');
}
$status = $this->resolveStatus($progress);
$this->progressRepo->save(
new LessonProgress($userId, $lessonId, $progress, $status)
);
}
private function assertProgressInRange(int $progress): void
{
if ($progress < self::PROGRESS_MIN || $progress > self::PROGRESS_MAX) {
throw new InvalidStateException('進度必須在 0-100 之間');
}
}
private function resolveStatus(int $progress): string
{
return $progress >= self::COMPLETION_THRESHOLD ? 'completed' : 'in_progress';
}
}
declare(strict_types=1);if 巢狀(Early Return)$wpdb$wpdb 查詢使用 prepare()vendor/bin/phpunit --testsuite integration
npx wp-env run tests-cli --env-cwd=wp-content/plugins/{plugin} \
vendor/bin/phpunit --testsuite integration
vendor/bin/phpunit tests/integration/Lesson/UpdateVideoProgressTest.php
vendor/bin/phpunit --filter test_成功增加影片進度 \
tests/integration/Lesson/UpdateVideoProgressTest.php
| 規則 | 說明 |
|---|---|
| R1 | 每步測試:每次修改後立即跑測試,紅燈立即還原該次修改 |
| R2 | 一次一件事:不同時改多處(一個命名 / 一次抽取 / 一個 Early Return) |
| R3 | 不改外部行為:公開 API 契約、資料庫 schema、WP Hook 名稱保持不變 |
| R4 | 不強行重構:已足夠清晰的程式碼保持原樣 |
| R5 | 禁止自動抽共用 helpers:除非使用者明確要求或三次以上重複 |
| R6 | 禁止跨檔搬動:優先於原檔內改善,避免一次性大規模檔案移動 |
| R7 | DRY 三次法則:重複出現三次以上才抽取 |
禁止在本階段做的事:
若發現需要上述變更 → 停止重構,回報使用者並建議另開新 Feature。
/zenbu-powers:aibdd.auto.php.it.code-quality 所有檢查項完成後輸出: