Jika Anda ingin refactor kecil di proyek CodeIgniter 4 berjalan konsisten tanpa menunggu review manual, pre-commit Rector adalah pendekatan yang masuk akal. Ide utamanya sederhana: sebelum kode masuk ke repository, hook Git menjalankan Rector pada file yang berubah untuk menerapkan refactor aman, misalnya modernisasi syntax PHP dan cleanup sederhana.

Pendekatan ini bukan pengganti formatter atau static analysis. Rector cocok untuk mengubah kode, PHP CS Fixer untuk merapikan style, dan PHPStan untuk menemukan potensi bug. Jika dipakai bersama dengan scope yang dibatasi, workflow ini membantu menjaga codebase tetap rapi tanpa membuat proses commit terasa berat.

Kapan Rector berguna dibanding PHP CS Fixer dan PHPStan

Rector: mengubah struktur kode secara otomatis

Rector berguna saat Anda ingin otomatisasi refactor yang sifatnya mekanis dan berulang. Contohnya:

  • Mengubah syntax lama ke syntax PHP yang lebih modern dan aman dibaca.
  • Merapikan pola kode sederhana yang bisa ditransformasi dengan aturan yang jelas.
  • Mengurangi pekerjaan review untuk perubahan yang seharusnya bisa dilakukan tool.

Rector bekerja pada level AST (abstract syntax tree), jadi ia memahami struktur kode, bukan sekadar mencari dan mengganti teks.

PHP CS Fixer: formatting dan style

PHP CS Fixer dipakai untuk konsistensi format, seperti penataan spasi, import, trailing comma, atau gaya penulisan array. Ia penting, tetapi bukan alat refactor struktural. Jika tujuan Anda adalah perubahan style tanpa mengubah perilaku program, gunakan PHP CS Fixer.

PHPStan: analisis statis untuk mendeteksi masalah

PHPStan tidak memodifikasi kode. Ia menganalisis tipe, alur data, pemanggilan method, nullability, dan berbagai potensi bug lain. Tool ini sangat cocok dijalankan di CI atau lokal sebelum push, tetapi tidak menyelesaikan kebutuhan refactor otomatis.

Pola kerja yang sehat

Untuk proyek CodeIgniter 4, pembagian tanggung jawab yang umum dan aman adalah:

  • Rector: refactor aman dan modernisasi syntax.
  • PHP CS Fixer: format dan style.
  • PHPStan: validasi kualitas dan potensi bug.

Jika pre-commit terasa lambat, prioritaskan Rector hanya untuk file yang di-stage. Jalankan pemeriksaan penuh di CI agar kualitas tetap terjaga.

Setup dependency dev untuk CodeIgniter 4

Pasang dependency sebagai dev dependency agar tidak ikut ke environment produksi. Minimal Anda membutuhkan Rector. Untuk hook Git, pilih salah satu: Husky atau CaptainHook.

Dependency dasar dengan Composer

composer require --dev rector/rector

Jika Anda juga memakai formatter dan static analysis dalam workflow yang sama, dependency terpisah bisa ditambahkan sesuai kebutuhan. Namun untuk fokus artikel ini, kita batasi ke Rector dan integrasi hook.

Pilihan integrasi hook

Ada dua pendekatan umum:

  • Husky: populer di tim yang sudah memakai Node.js tooling, misalnya untuk frontend, lint-staged, atau commit workflow lain.
  • CaptainHook: lebih natural untuk ekosistem PHP karena hook dikelola dari dependency proyek PHP.

Jika proyek CodeIgniter 4 Anda murni PHP dan tidak memakai Node.js, CaptainHook biasanya lebih ringan secara operasional. Jika repository sudah punya toolchain JavaScript, Husky sering lebih mudah diterima karena satu pola untuk semua hook.

Konfigurasi dasar Rector untuk refactor aman

Target pre-commit sebaiknya konservatif. Jangan langsung mengaktifkan aturan besar yang mengubah arsitektur atau kontrak API. Fokus pada modernisasi syntax PHP dan cleanup sederhana yang relatif aman untuk dijalankan sering.

Contoh file konfigurasi rector.php

<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\SetList;

return static function (RectorConfig $rectorConfig): void {
    $rectorConfig->paths([
        __DIR__ . '/app',
        __DIR__ . '/tests',
    ]);

    $rectorConfig->skip([
        __DIR__ . '/vendor',
        __DIR__ . '/writable',
        __DIR__ . '/public',
    ]);

    $rectorConfig->sets([
        SetList::CODE_QUALITY,
        SetList::DEAD_CODE,
    ]);

    $rectorConfig->phpVersion(\Rector\ValueObject\PhpVersion::PHP_80);
};

Catatan penting:

  • Batasi path ke app dan tests. Ini biasanya cukup untuk target CodeIgniter 4.
  • Skip directory yang tidak relevan agar hook tetap cepat.
  • Pilih set secara konservatif. Jangan langsung menyalakan semua aturan upgrade atau framework-specific rule tanpa review.
  • PHP version harus disesuaikan dengan versi PHP minimal yang benar-benar dipakai proyek Anda.

Mengapa konfigurasi konservatif lebih aman

Rector bisa sangat kuat, tetapi kekuatan itu juga berarti ada risiko perubahan yang terlalu agresif. Pada tahap awal adopsi, tujuan utama bukan mengejar transformasi sebanyak mungkin, melainkan memastikan hasil refactor:

  • mudah diprediksi,
  • mudah direview di diff,
  • tidak memperlambat commit harian,
  • tidak mengejutkan anggota tim.

Contoh target refactor pada controller, service, dan test

Di bawah ini bukan daftar semua rule Rector, melainkan contoh area yang cocok menjadi target pre-commit karena manfaatnya jelas dan risikonya relatif rendah.

Controller: cleanup dan modernisasi syntax sederhana

<?php

namespace App\Controllers;

use App\Services\UserService;
use CodeIgniter\Controller;

class UserController extends Controller
{
    public function show(int $id)
    {
        $service = new UserService();

        if ($id === 0) {
            return redirect()->to('/users');
        }

        $user = $service->findById($id);

        if ($user === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        return view('users/show', ['user' => $user]);
    }
}

Pada kode semacam ini, Rector cocok untuk cleanup aman seperti menyederhanakan pola tertentu, menghapus kode mati sederhana, atau membantu modernisasi syntax. Namun ia tidak boleh dipaksa mengambil keputusan desain seperti mengganti cara dependency di-instantiate jika proyek Anda belum punya pola DI yang konsisten.

Service: refactor kecil yang berulang

<?php

namespace App\Services;

class InvoiceService
{
    public function normalizeStatus(?string $status): string
    {
        return $status ?? 'draft';
    }
}

Pada kelas service, Rector sering berguna untuk transformasi syntax yang berulang di banyak file. Misalnya penyederhanaan ekspresi yang ekuivalen secara perilaku. Ini mengurangi noise saat developer melakukan perubahan domain yang sebenarnya kecil.

Test: menjaga test suite tetap konsisten

<?php

namespace Tests\Unit\Services;

use App\Services\InvoiceService;
use CodeIgniter\Test\CIUnitTestCase;

class InvoiceServiceTest extends CIUnitTestCase
{
    public function testNormalizeStatusReturnsDraftWhenNull(): void
    {
        $service = new InvoiceService();

        $this->assertSame('draft', $service->normalizeStatus(null));
    }
}

Folder tests adalah target yang baik untuk Rector karena perubahan syntax di test umumnya lebih aman. Selain itu, test yang rapi mempercepat review dan mempermudah migrasi bertahap.

Menjalankan Rector hanya pada file yang di-stage

Kunci agar pre-commit tidak mengganggu flow harian adalah scope yang sempit. Jangan jalankan Rector ke seluruh proyek pada setiap commit. Jalankan hanya pada file PHP yang sedang di-stage.

Pendekatan umum

  1. Ambil daftar file yang di-stage dari Git.
  2. Filter hanya file berekstensi .php.
  3. Batasi ke path yang relevan, misalnya app/ dan tests/.
  4. Jalankan Rector pada daftar file tersebut.
  5. Tambahkan kembali file yang diubah oleh Rector ke staging area.

Contoh script shell sederhana

#!/bin/sh

FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '^(app|tests)/.*\.php$')

if [ -z "$FILES" ]; then
  exit 0
fi

vendor/bin/rector process $FILES --no-progress-bar
STATUS=$?

if [ $STATUS -ne 0 ]; then
  echo "Rector gagal. Periksa output di atas."
  exit $STATUS
fi

printf '%s\n' "$FILES" | xargs git add

Script ini menunjukkan pola kerja yang penting: file yang diubah otomatis oleh Rector harus di-stage ulang, jika tidak commit bisa berisi versi lama.

Integrasi Git hook dengan Husky

Jika repository Anda sudah memakai Node.js tooling, Husky bisa menjadi pilihan yang praktis.

Contoh alur integrasi

  1. Pasang Husky di repository.
  2. Buat hook pre-commit.
  3. Panggil script shell yang menjalankan Rector pada file staged.
npx husky init

Lalu isi file hook pre-commit dengan pemanggilan script proyek, misalnya:

./tools/pre-commit-rector.sh

Keuntungan Husky:

  • Cocok jika tim sudah akrab dengan hook berbasis Node.js.
  • Mudah digabung dengan linting frontend atau commit workflow lain.

Kekurangannya:

  • Menambah dependency dan runtime tambahan untuk proyek PHP murni.
  • Butuh konsistensi environment lokal jika sebagian developer tidak memasang tool Node.js.

Integrasi Git hook dengan CaptainHook

Untuk tim PHP-first, CaptainHook sering terasa lebih natural karena dikelola dari ekosistem PHP.

Contoh pendekatan konfigurasi

Pasang package CaptainHook sebagai dev dependency, lalu definisikan action pre-commit untuk memanggil script yang sama. Struktur pastinya dapat mengikuti dokumentasi resmi package yang Anda gunakan, tetapi prinsipnya tetap:

  • Hook tidak perlu mengetahui detail Rector.
  • Logika filter file staged disimpan di script proyek agar mudah dirawat.
  • Tool hook hanya menjadi pemicu.

Keuntungan CaptainHook:

  • Lebih konsisten untuk proyek berbasis Composer.
  • Tidak bergantung pada Node.js jika memang tidak dibutuhkan.

Kekurangannya:

  • Kurang familiar di tim yang sudah menstandardkan Husky di semua repository.

Membatasi scope agar hook tetap cepat

Masalah paling umum pada pre-commit Rector bukan akurasi, melainkan performa dan gangguan pada ritme kerja developer. Beberapa strategi berikut biasanya cukup efektif:

1. Proses hanya file staged

Ini aturan paling penting. Menjalankan Rector ke seluruh codebase pada setiap commit hampir selalu terasa terlalu berat.

2. Batasi path

Fokus pada app dan tests. Hindari memproses direktori build, cache, public asset, atau generated code.

3. Mulai dari rule yang aman

Semakin agresif ruleset, semakin besar kemungkinan waktu proses bertambah dan diff menjadi sulit direview.

4. Pisahkan mode lokal dan mode CI

Lokal untuk file staged saja. CI untuk full run pada seluruh project.

5. Hindari terlalu banyak tool berat di pre-commit

Jika pre-commit sudah menjalankan Rector, formatter, test, dan static analysis penuh sekaligus, developer cenderung mencari cara untuk melewati hook. Itu tanda workflow perlu disederhanakan.

Strategi menjalankan cek penuh di CI

Pre-commit sebaiknya dianggap sebagai filter cepat, bukan satu-satunya lapisan kualitas. Di CI, jalankan pemeriksaan yang lebih lengkap:

  • Rector pada seluruh path target untuk memastikan tidak ada file yang terlewat.
  • PHPStan untuk analisis statis.
  • Formatter atau style checker untuk konsistensi style.
  • Test suite sesuai tingkat kepercayaan yang dibutuhkan.

Mode CI yang umum

Untuk CI, banyak tim memilih mode dry-run atau mode yang membuat pipeline gagal jika ada perubahan yang seharusnya diterapkan. Dengan begitu, CI bertindak sebagai pagar terakhir tanpa diam-diam mengubah kode di branch build.

Prinsip yang aman: lokal boleh memperbaiki otomatis, CI sebaiknya memverifikasi dan gagal jika ada deviasi.

Risiko false positive, keterbatasan, dan cara menguranginya

False positive tetap mungkin terjadi

Walaupun Rector memahami struktur kode, tidak semua transformasi aman untuk semua codebase. Risiko muncul terutama jika proyek memiliki pola dinamis, magic method, convention internal, atau integrasi framework yang bergantung pada perilaku implisit.

Keterbatasan yang perlu diingat

  • Rector tidak memahami seluruh niat bisnis di balik kode.
  • Transformasi yang tampak valid secara syntax belum tentu sesuai kontrak internal proyek.
  • Kode dengan refleksi, proxy, atau pola meta-programming lebih rentan terhadap perubahan yang tidak diinginkan.

Cara mengurangi risiko

  • Mulai dari ruleset konservatif.
  • Jalankan pada area yang ter-cover test.
  • Review diff hasil refactor, jangan langsung commit tanpa melihat perubahan.
  • Tambahkan skip untuk file atau folder yang sering bermasalah.
  • Gunakan CI untuk memverifikasi bahwa perubahan otomatis tidak merusak perilaku aplikasi.

Cara review diff hasil refactor otomatis

Salah satu kesalahan umum adalah menganggap hasil Rector selalu benar lalu langsung commit. Praktik yang lebih aman:

  1. Jalankan Rector di pre-commit.
  2. Lihat diff sebelum commit final.
  3. Pastikan perubahan hanya bersifat mekanis dan tidak mengubah maksud kode.
  4. Jika ada refactor yang terasa terlalu agresif, tambahkan pengecualian di konfigurasi.

Apa yang perlu dicek saat review diff

  • Apakah perubahan hanya syntax dan cleanup sederhana?
  • Apakah ada perubahan pada perilaku null handling, perbandingan, atau casting?
  • Apakah file test ikut menyesuaikan secara masuk akal?
  • Apakah perubahan membuat code review domain menjadi lebih sulit karena tercampur noise?

Jika jawabannya ya pada poin terakhir, pertimbangkan untuk memisahkan commit refactor otomatis dari commit perubahan fitur.

Checklist adopsi tim agar tidak mengganggu flow commit harian

Agar pre-commit Rector diterima tim, fokuslah pada adopsi bertahap.

Checklist praktis

  • Sepakati tujuan: hook dipakai untuk refactor kecil dan aman, bukan migrasi besar.
  • Batasi rule awal: mulai dari modernisasi syntax dan cleanup sederhana.
  • Proses hanya file staged: jangan seluruh codebase.
  • Dokumentasikan cara bypass darurat: misalnya saat debugging hook bermasalah, dengan catatan penggunaan harus jarang dan jelas.
  • Pisahkan validasi penuh ke CI: jangan semua beban diletakkan di lokal.
  • Review diff tetap wajib: hasil otomatis bukan berarti bebas audit.
  • Tambahkan skip list: untuk area sensitif, generated code, atau folder legacy tertentu.
  • Mulai dari satu repository: ukur dampak ke kecepatan commit sebelum diterapkan lebih luas.

Rekomendasi workflow yang realistis untuk CodeIgniter 4

Jika Anda ingin mulai tanpa banyak risiko, workflow berikut cukup seimbang:

  1. Pasang Rector sebagai dev dependency.
  2. Buat rector.php dengan path app dan tests, plus set yang konservatif.
  3. Buat script pre-commit yang hanya memproses file PHP staged.
  4. Integrasikan script ke Husky atau CaptainHook sesuai toolchain tim.
  5. Di CI, jalankan Rector untuk seluruh target dalam mode verifikasi, lalu jalankan PHPStan dan test.
  6. Evaluasi diff selama beberapa sprint sebelum menambah ruleset.

Dengan pola ini, CodeIgniter 4 pre-commit Rector memberi manfaat nyata: refactor kecil terjadi lebih konsisten, review menjadi lebih fokus pada logika bisnis, dan codebase bergerak ke arah yang lebih rapi tanpa mengubah flow commit harian secara drastis.