Diagnose: Was Vibe-Codebases typischerweise haben
Vibe-Codebases zeigen wiederkehrende Muster: God-Classes mit 800+ Zeilen, SQL in Controllern, Copy-Paste zwischen Features, fehlende Namespaces, Tests nur für „das letzte Feature“. Der Agent hat funktional geliefert – aber ohne Architektur-Intent.
Bevor refactoriert wird, kartieren wir: Hotspots (hohe Änderungsfrequenz + hohe Komplexität), Domain-Grenzen (was gehört zusammen?), und Agent-Risiko (wo würde ein Agent am meisten Schaden anrichten?). Diese Karte steuert die Strangler-Reihenfolge.
Wichtig: Nicht alles muss sofort perfekt sein. Agenticode priorisiert nach Business-Risiko und Änderungsfrequenz – nicht nach akademischer Schönheit.
<?php
declare(strict_types=1);
namespace App\Refactoring\Analysis;
final class VibeCodebaseHotspotAnalyzer
{
public function findHotspots(string $srcDir, int $limit = 10): array
{
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($srcDir)
);
$scores = [];
foreach ($files as $file) {
if ($file->getExtension() !== 'php') {
continue;
}
$path = $file->getPathname();
$lines = count(file($path) ?: []);
$churn = $this->gitChurnLast90Days($path);
$scores[$path] = $lines * log(1 + $churn);
}
arsort($scores);
return array_slice($scores, 0, $limit, true);
}
private function gitChurnLast90Days(string $path): int
{
$out = shell_exec(
'git log --since=90.days --numstat -- ' . escapeshellarg($path) . ' 2>/dev/null'
) ?: '';
return substr_count($out, "\n");
}
}
Strangler-Fig mit agentischen Sub-Loops
Der Strangler-Fig extrahiert Schicht für Schicht: zuerst Domain-Models, dann Services, dann Persistence, zuletzt Controller-Wiring. Jede Extraktion ist ein abgeschlossener Agent-Run mit engem Scope und eigenem Verification-Set.
Während der Extraktion bleibt die alte Implementierung als Fassade erhalten. Neue Aufrufer nutzen die extrahierte Schicht; Legacy-Code wird markiert und später entfernt. So ist das System jederzeit deploybar.
Multi-Agent-Orchestrierung hilft: Planner definiert Extraktions-Reihenfolge, Implementer extrahiert, Tester sichert Verhalten mit Characterization Tests, Reviewer prüft Architektur-Compliance.
<?php
declare(strict_types=1);
namespace App\Billing;
/**
* @deprecated Use InvoiceService::create() – Strangler step 3/4
*/
final class LegacyBillingFacade
{
public function __construct(
private readonly InvoiceService $invoiceService,
) {}
public function createInvoice(array $legacyPayload): array
{
$dto = InvoiceCreateDto::fromLegacyArray($legacyPayload);
$invoice = $this->invoiceService->create($dto);
return $invoice->toLegacyArray(); // backward compatible response
}
}
Harte Lint-Grenzen nach dem Prototyp
Refactoring ohne Grenzen driftet zurück in Vibe-Territorium. Agenticode etabliert PHPStan Level 8, Custom Rules (kein SQL in Controllers, max. Dateigröße), und PHP-CS-Fixer als Pre-Commit-Hook. Agents dürfen nur committen, wenn alle Grenzen grün sind.
Characterization Tests sichern Legacy-Verhalten vor der Extraktion: Sie dokumentieren Ist-Zustand, nicht Soll-Zustand. Sobald grün, kann refactored werden – mit Confidence, dass externe Verhalten gleich bleiben.
Am Ende einer Agenticode-Refactoring-Engagement-Phase haben Sie: modulare Struktur, grüne CI, Cursor Rules die zukünftige Agent-Runs im Gleis halten, und ein Team, das versteht, wie weitergebaut wird.
# phpstan-custom-rules/refactoring-gates.neon
parameters:
agenticodeRules:
maxFileLines: 400
forbiddenInControllers:
- PDO
- mysqli
- raw SQL strings
requiredTestSuffix:
Service: Test
Repository: Test
services:
- class: App\PhpStan\NoSqlInControllerRule
- class: App\PhpStan\MaxFileLinesRule