Kode yang berjalan belum tentu kode yang baik. Setiap developer pernah membuka controller berisi tiga ratus baris, dengan nama variabel $data2, if bersarang lima tingkat, dan angka 3 yang entah berarti apa. Mengubah satu aturan diskon di kode seperti itu bisa memakan setengah hari, dan sering merusak fitur lain tanpa disadari. Clean code adalah kebiasaan menulis kode yang mudah dibaca dan aman diubah, terutama oleh orang lain, termasuk diri Anda sendiri enam bulan kemudian.
Artikel ini membahas prinsip-prinsip yang paling terasa dampaknya di proyek Laravel sehari-hari, masing-masing dengan contoh kode sebelum dan sesudah dirapikan.
1. Nama yang Menjelaskan Maksud
Nama adalah dokumentasi yang paling sering dibaca. Nama yang baik menjawab "ini apa" dan "untuk apa" tanpa perlu membuka isi fungsinya.
// Sulit dipahami
$d = 30;
$x = Order::where('s', 2)->get();
function proses($a) { ... }
// Jelas
$batasHariJatuhTempo = 30;
$pesananBelumDibayar = Order::where('status', OrderStatus::Menunggu)->get();
function kirimPengingatTagihan(Order $order) { ... }
Pedoman praktis: variabel dan properti memakai kata benda ($totalBelanja), fungsi memakai kata kerja (hitungDiskon()), nilai boolean diawali is, has, atau bisa ($isLunas). Konsisten memakai satu bahasa dalam satu proyek juga membantu; campuran getPelanggan() dan ambilCustomer() membingungkan pembaca.
2. Kurangi If Bersarang dengan Early Return
Kode yang terus menjorok ke kanan memaksa pembaca mengingat banyak kondisi sekaligus. Tangani kasus gagal lebih dulu, lalu keluar.
// Sebelum: tiga tingkat if
public function bayar(Order $order)
{
if ($order->user_id === auth()->id()) {
if ($order->status === 'menunggu') {
if ($order->total > 0) {
// ... proses pembayaran
}
}
}
}
// Sesudah: guard clause, alur utama tidak menjorok
public function bayar(Order $order)
{
Gate::authorize('pay', $order);
if ($order->status !== OrderStatus::Menunggu) {
return back()->with('error', 'Pesanan ini sudah diproses.');
}
if ($order->total <= 0) {
return back()->with('error', 'Total pesanan tidak valid.');
}
// ... proses pembayaran
}
3. Ganti Angka dan Teks Ajaib dengan Enum atau Konstanta
Angka 2 pada where('status', 2) tidak berarti apa-apa bagi pembaca baru, dan salah ketik 'lunass' tidak akan ketahuan sampai ada laporan bug. Sejak PHP 8.1, gunakan enum:
// app/Enums/OrderStatus.php
enum OrderStatus: string
{
case Menunggu = 'menunggu';
case Lunas = 'lunas';
case Batal = 'batal';
public function label(): string
{
return match ($this) {
self::Menunggu => 'Menunggu Pembayaran',
self::Lunas => 'Lunas',
self::Batal => 'Dibatalkan',
};
}
}
// app/Models/Order.php
protected function casts(): array
{
return ['status' => OrderStatus::class];
}
// Pemakaian
if ($order->status === OrderStatus::Lunas) { ... }
Editor sekarang bisa melengkapi nilai yang valid, salah ketik langsung menjadi error, dan label tampilan berada di satu tempat.
4. Controller Tipis: Pindahkan Validasi dan Logika Bisnis
Controller yang sehat cukup menerima request, memanggil logika, dan mengembalikan respons. Validasi dipindahkan ke Form Request, logika bisnis ke kelas tersendiri (sering disebut Action atau Service).
php artisan make:request StoreOrderRequest
// app/Http/Requests/StoreOrderRequest.php
public function rules(): array
{
return [
'items' => ['required', 'array', 'min:1'],
'items.*.product_id' => ['required', 'exists:products,id'],
'items.*.qty' => ['required', 'integer', 'min:1'],
];
}
// app/Actions/BuatPesanan.php
class BuatPesanan
{
public function handle(User $user, array $items): Order
{
return DB::transaction(function () use ($user, $items) {
$order = $user->orders()->create(['status' => OrderStatus::Menunggu]);
foreach ($items as $item) {
$product = Product::lockForUpdate()->findOrFail($item['product_id']);
$product->decrement('stock', $item['qty']);
$order->items()->create([
'product_id' => $product->id,
'qty' => $item['qty'],
'price' => $product->price,
]);
}
return $order;
});
}
}
// Controller menjadi sangat ringkas
public function store(StoreOrderRequest $request, BuatPesanan $buatPesanan)
{
$order = $buatPesanan->handle($request->user(), $request->validated()['items']);
return redirect()->route('orders.show', $order);
}
Keuntungannya nyata: logika BuatPesanan bisa dipakai ulang dari API atau command artisan, dan bisa diuji tanpa melewati HTTP. Detail aturan validasi dibahas di validasi form di Laravel dengan rapi.
5. Satu Fungsi, Satu Tanggung Jawab
Fungsi bernama simpanDanKirimEmailDanUpdateStok() adalah tanda fungsi itu mengerjakan terlalu banyak hal. Pecah menjadi beberapa fungsi kecil dengan nama yang jelas. Patokan sederhana: jika Anda kesulitan memberi nama tanpa kata "dan", atau fungsi tidak muat dalam satu layar, kemungkinan besar ia perlu dipecah.
6. DRY, tetapi Jangan Abstraksi Terlalu Dini
Prinsip Don't Repeat Yourself mengajak menghindari duplikasi logika. Namun menyatukan dua kode yang hanya kebetulan mirip sering berakhir dengan satu fungsi penuh parameter $mode dan if di mana-mana. Pegangan yang lebih aman: tunggu sampai pola yang sama muncul tiga kali dan alasannya memang sama, baru buat abstraksi.
7. Komentar Menjelaskan "Kenapa", Bukan "Apa"
// Buruk: mengulang apa yang sudah jelas dari kode
// tambah 1 ke counter
$counter++;
// Baik: menjelaskan alasan yang tidak terlihat dari kode
// Bank mitra hanya menerima nominal kelipatan 100, sisa pembulatan masuk biaya admin.
$nominalTransfer = floor($total / 100) * 100;
Jika sebuah blok kode butuh komentar panjang untuk menjelaskan apa yang dilakukannya, biasanya lebih baik dipindah ke fungsi dengan nama yang menjelaskan hal tersebut.
8. Biarkan Alat yang Menjaga Format
Perdebatan soal spasi dan letak kurung kurawal membuang waktu review. Proyek Laravel baru sudah menyertakan Laravel Pint:
vendor/bin/pint # merapikan seluruh kode
vendor/bin/pint --test # hanya mengecek, cocok untuk CI
Jalankan pint --test otomatis di setiap push seperti dijelaskan di CI/CD sederhana dengan GitHub Actions, sehingga review kode bisa fokus pada logika.
9. Test Membuat Refactor Aman
Merapikan kode tanpa test sama dengan merenovasi rumah dalam gelap. Sebelum memindahkan logika dari controller ke Action, tulis dulu feature test untuk alur tersebut, pastikan lulus, baru refactor dan jalankan ulang. Panduan memulainya ada di testing otomatis di Laravel untuk pemula.
Tanda-Tanda Kode Perlu Dirapikan
| Gejala | Langkah perbaikan |
|---|---|
| Controller lebih dari 200 baris | Pindahkan validasi ke Form Request, logika ke Action |
| If bersarang lebih dari dua tingkat | Early return / guard clause |
| Angka atau string status tersebar di banyak file | Enum dengan cast di model |
| Kode yang sama disalin di tiga tempat atau lebih | Ekstrak ke method, Action, atau scope Eloquent |
| Query berulang dengan kondisi yang sama | Local scope, lihat mengenal Eloquent ORM |
| Takut mengubah kode karena sering merusak fitur lain | Tulis feature test lebih dulu, baru refactor |
Clean code tidak harus dikerjakan sekaligus. Terapkan aturan sederhana: setiap kali menyentuh sebuah file, tinggalkan dalam keadaan sedikit lebih rapi daripada saat Anda membukanya.