Fundamental Pull Request #

Pull Request (PR) adalah salah satu aktivitas yang paling sering dilakukan engineer tapi paling jarang dipahami secara mendalam. Bagi sebagian tim, PR adalah formalitas — checklist sebelum merge. Bagi tim yang lebih matang, PR adalah pusat dari kolaborasi engineering: tempat di mana keputusan teknikal didiskusikan, pengetahuan tersebar, dan kualitas kode dijaga sebelum menyentuh production. Perbedaan antara kedua tim ini bukan pada tool yang digunakan — melainkan pada cara mereka memaknai PR dan code review. Artikel ini membahas fondasi yang paling mendasar dari praktik ini.

Apa Itu Pull Request? #

Pull Request adalah mekanisme untuk mengusulkan perubahan kode dari sebuah branch ke branch lain — biasanya dari feature branch ke main atau develop — agar perubahan tersebut dapat ditinjau, didiskusikan, dan divalidasi sebelum menjadi bagian dari codebase utama.

Tapi definisi teknikal itu hanya setengah dari ceritanya. Secara lebih dalam, PR adalah kontrak sosial antar engineer:

PR sebagai kontrak sosial berarti:
  ✓ Author berkomitmen: "Kode ini sudah saya pikirkan, saya test, dan saya siap
                         pertanggungjawabkan. Saya mengundang perspektif lain."
  ✓ Reviewer berkomitmen: "Saya akan memberikan feedback yang konstruktif dan tepat waktu
                           untuk membantu kode ini menjadi lebih baik."
  ✓ Tim berkomitmen: "Tidak ada kode yang masuk ke codebase utama tanpa melewati proses ini."

PR bukan “izin merge dari atasan” dan bukan “langkah prosedural yang harus dilalui”. Ia adalah mekanisme kolaborasi yang dirancang untuk membuat keputusan teknikal lebih baik dari yang bisa dihasilkan satu engineer sendirian.


Apa Itu Code Review? #

Code Review adalah proses meninjau perubahan kode dalam sebuah PR — membacanya, memahami konteksnya, mempertanyakan asumsinya, dan memberikan feedback yang membantu author menghasilkan kode yang lebih baik.

Kata kunci: membantu, bukan menghakimi. Code review yang baik adalah dialog teknikal antara dua engineer yang sama-sama ingin kodebase menjadi lebih baik. Bukan audit, bukan interogasi, bukan sesi membuktikan siapa yang lebih pintar.

flowchart LR
    subgraph Persepsi yang salah
        A1[Author\nmenulis kode] --> B1[Reviewer\nmencari kesalahan]
        B1 --> C1[Author\nmempertahankan diri]
        C1 --> D1[Ketegangan,\nreview lambat]
    end

    subgraph Persepsi yang benar
        A2[Author\nmenulis kode] --> B2[Reviewer\nmembantu memperbaiki]
        B2 --> C2[Author\nmenerima & berdiskusi]
        C2 --> D2[Kode lebih baik,\nkeduanya belajar]
    end

Mengapa PR dan Code Review Penting? #

Quality Gate Sebelum Production #

Bug yang ditemukan di code review jauh lebih murah diperbaiki daripada bug yang ditemukan di production. Tidak ada monitoring atau alerting yang bisa menggantikan sepasang mata engineer yang memahami konteks bisnis dan teknikal.

Biaya menemukan bug di berbagai tahap:
  Di code review    → edit kode, push ulang (menit hingga jam)
  Di QA/staging     → assign ke developer, fix, retest (hari)
  Di production     → hotfix, incident response, potensial data impact (hari hingga minggu)

// Satu komentar di code review yang mencegah bug production
// bisa menghemat 10x waktu tim

Mendistribusikan Pengetahuan #

Kode yang tidak pernah direview adalah kode yang hanya dipahami oleh satu orang. Setiap PR yang direview dengan sungguh-sungguh adalah sesi knowledge transfer — reviewer belajar tentang perubahan yang dibuat, author belajar dari perspektif yang berbeda.

flowchart TD
    PR[Pull Request] --> A[Author\nmendapat perspektif baru]
    PR --> B[Reviewer\nmemahami perubahan sistem]
    PR --> C[Tim yang membaca thread\nbelajar dari diskusi]
    PR --> D[Engineer di masa depan\nbisa membaca konteks di komentar PR]

Membangun Standar Kode Secara Organik #

Tim yang konsisten melakukan code review secara otomatis membangun shared understanding tentang apa yang dianggap kode yang baik — tanpa perlu dokumen standar yang panjang. Standar ini terbentuk dari diskusi yang terjadi di PR, bukan dari aturan yang ditetapkan dari atas.

Menjadi Dokumentasi Keputusan Teknikal #

Diskusi di PR adalah dokumentasi yang paling jujur tentang mengapa sebuah kode ditulis dengan cara tertentu. Ketika ada pertanyaan “kenapa kita dulu memilih pendekatan ini?”, jawabannya sering ada di thread PR lama.


Filosofi Dasar yang Harus Dipegang #

Kode adalah Aset Tim, Bukan Milik Individu #

Ini adalah perubahan pola pikir yang paling mendasar. Ketika engineer memperlakukan kode sebagai “kode saya”, mereka cenderung defensif saat direview. Ketika kode diperlakukan sebagai aset tim, review menjadi kolaborasi untuk meningkatkan aset bersama.

// ✗ Pola pikir individual
"Ini kode saya, kamu tidak perlu ubah cara saya coding"
"Saya sudah punya cara sendiri, tidak perlu direview"

// ✓ Pola pikir tim
"Kode ini akan dimaintain tim selama bertahun-tahun — saya ingin
 memastikan orang lain bisa memahami dan mengubahnya dengan mudah"
"Review ini membantu kode yang akan masuk ke codebase tim menjadi lebih baik"

Review Kode, Bukan Orang #

Semua feedback dalam code review harus diarahkan ke kode dan keputusan teknikal — bukan ke karakter, kemampuan, atau kepintaran penulisnya.

// ✗ Review yang menyerang orang
"Ini salah. Kenapa kamu tidak berpikir lebih dulu?"
"Pendekatan ini menunjukkan kamu tidak paham arsitektur kita"

// ✓ Review yang fokus pada kode
"Pendekatan ini bisa menimbulkan race condition ketika ada concurrent request.
 Pertimbangkan menggunakan mutex di sini — ini contoh yang relevan: [link]"
"Ada cara yang lebih idiomatic untuk ini di Go: [contoh kode]
 Ini akan lebih mudah dibaca oleh engineer yang baru bergabung"

Clarity di Atas Cleverness #

Kode yang pintar dan sulit dipahami adalah beban, bukan aset. Kode yang jelas dan mudah dipahami — meskipun sedikit lebih verbose — jauh lebih berharga dalam jangka panjang.

// ✗ Clever tapi sulit dipahami
result := lo.Filter(users, func(u User, _ int) bool { return u.Active && u.Age >= 18 && !u.Banned })

// ✓ Clear dan mudah dipahami
eligibleUsers := filterEligibleUsers(users)

func filterEligibleUsers(users []User) []User {
    var eligible []User
    for _, u := range users {
        if u.Active && u.Age >= 18 && !u.Banned {
            eligible = append(eligible, u)
        }
    }
    return eligible
}

PR adalah Percakapan, Bukan Checklist #

PR yang baik tidak selesai hanya karena semua komentar sudah direspons. Ia selesai ketika semua pihak merasa kode yang akan dimerge adalah versi terbaik yang bisa dihasilkan dengan waktu dan konteks yang ada.


Siklus Hidup Pull Request #

Memahami siklus hidup PR membantu engineer mengetahui peran dan tanggung jawab mereka di setiap tahap:

stateDiagram-v2
    [*] --> Draft: Author mulai coding
    Draft --> ReadyForReview: Self-review selesai, CI lulus
    ReadyForReview --> InReview: Reviewer mulai membaca
    InReview --> ChangesRequested: Reviewer menemukan hal yang perlu diperbaiki
    ChangesRequested --> ReadyForReview: Author menyelesaikan feedback
    InReview --> Approved: Reviewer puas dengan perubahan
    Approved --> Merged: Merge ke branch target
    Merged --> [*]
    InReview --> Closed: PR tidak dilanjutkan
    Closed --> [*]
StatusTanggung Jawab AuthorTanggung Jawab Reviewer
DraftMenyelesaikan implementasi, self-reviewBoleh memberikan feedback awal jika diminta
Ready for ReviewMemastikan deskripsi lengkap dan CI lulusMulai review dalam SLA yang disepakati
In ReviewSiap merespons pertanyaanMemberikan feedback yang jelas dan konstruktif
Changes RequestedMenyelesaikan feedback, reply setiap komentarMelakukan re-review setelah author update
ApprovedMerge setelah semua kondisi terpenuhiSiap jika ada pertanyaan tambahan

Prinsip Fundamental Pull Request (Sisi Author) #

Satu PR, Satu Tujuan #

PR yang mencampur feature baru, refactor besar, dan perbaikan bug sekaligus adalah PR yang tidak bisa direview dengan baik. Reviewer tidak bisa fokus karena harus memahami terlalu banyak konteks sekaligus.

// ✗ PR yang mencampur terlalu banyak
PR: "Update payment flow"
  - Tambah fitur multi-currency (300 baris)
  - Refactor seluruh payment service (500 baris)
  - Fix bug timeout (20 baris)
  - Update dependency grpc-go (50 baris)
→ Reviewer tidak tahu harus fokus ke mana
→ Bug di feature baru tersembunyi di balik banyaknya perubahan

// ✓ PR yang fokus
PR 1: "Add multi-currency support to payment flow" (300 baris)
PR 2: "Fix payment service timeout bug" (20 baris)
PR 3: "Update grpc-go dependency" (50 baris)
→ Setiap PR bisa direview secara independen
→ Bug lebih mudah terdeteksi
→ Jika ada masalah, mudah di-rollback per PR

Ukuran PR yang Dapat Direview #

PR yang terlalu besar tidak akan direview dengan kualitas yang baik — reviewer akan kehilangan fokus atau melakukan approval theater (approve tanpa benar-benar membaca).

Target ukuran PR:
  ✓ < 300 baris: ideal, bisa direview dalam 30–45 menit
  ⚠ 300–600 baris: bisa, tapi butuh reviewer yang fokus
  ✗ > 600 baris: sangat sulit untuk direview dengan baik

Jika PR harus besar (misalnya refactor yang tidak bisa dipecah):
  ✓ Jelaskan strukturnya di deskripsi — mana yang harus dibaca pertama
  ✓ Gunakan komentar di PR untuk menunjukkan bagian yang paling penting
  ✓ Pertimbangkan review meeting terpisah untuk PR yang sangat besar

Deskripsi PR adalah Bagian dari Kode #

Deskripsi yang baik menghemat waktu reviewer lebih dari apapun. Reviewer yang memahami konteks PR akan memberikan feedback yang lebih relevan dan tepat sasaran.

// ✗ Deskripsi yang tidak membantu
Title: "Fix bug"
Description: "Fixed the issue"

// ✓ Deskripsi yang memberikan konteks penuh
Title: "Fix race condition on concurrent order status update"

## Latar Belakang
Terdapat race condition ketika dua request memperbarui status order yang sama
secara bersamaan. Hal ini menyebabkan status order bisa kembali ke status sebelumnya
jika kedua request berhasil tapi dengan urutan commit yang berbeda dari yang diharapkan.

## Perubahan
- Tambahkan optimistic locking menggunakan version field pada tabel orders
- Update repository layer untuk mendeteksi concurrent update dan return error yang jelas
- Tambahkan retry logic di service layer untuk kasus version conflict

## Dampak
- Endpoint PATCH /orders/{id}/status sekarang bisa menangani concurrent request dengan aman
- Tidak ada perubahan breaking di API contract
- Performa tidak terpengaruh secara signifikan (benchmark terlampir)

## Cara Testing
1. Jalankan `go test ./internal/order/...`
2. Untuk test concurrent: `go test -race ./internal/order/...`
3. Manual test: buka dua tab, update status order yang sama bersamaan

Self-Review Sebelum Minta Review #

Engineer yang me-review kode mereka sendiri sebelum membuka PR untuk orang lain akan menemukan sebagian besar komentar yang seharusnya datang dari reviewer — dan menghemat waktu semua orang.

Checklist self-review sebelum PR dibuka:
  □ Baca seluruh diff dari perspektif reviewer yang belum tahu konteksnya
  □ Pastikan tidak ada debug code, console.log, atau komentar sementara
  □ Pastikan nama variabel dan fungsi jelas dan konsisten
  □ Pastikan tidak ada kode yang di-comment-out tanpa penjelasan
  □ Pastikan tidak ada TODO yang terlupakan tanpa tiket terkait
  □ Pastikan CI (test, lint, build) sudah lulus sebelum PR dibuka

Prinsip Fundamental Code Review (Sisi Reviewer) #

Prioritaskan Hal yang Paling Penting #

Tidak semua komentar code review memiliki bobot yang sama. Reviewer yang tidak memprioritaskan sering menghabiskan waktu untuk hal-hal minor sementara melewatkan masalah yang lebih kritis.

Prioritas code review (dari yang paling penting):
  1. Correctness: apakah kode ini melakukan apa yang seharusnya?
     → Bug logic, off-by-one error, null pointer, race condition
  2. Security: apakah ada vulnerability yang terekspos?
     → Input validation, SQL injection, exposed credentials, insecure random
  3. Design & Architecture: apakah ini sesuai dengan arsitektur yang disepakati?
     → Melanggar layer boundary, coupling yang tidak perlu, violation of RFC
  4. Performance: apakah ada masalah performa yang signifikan?
     → N+1 query, unnecessary loop, memory leak
  5. Readability: apakah kode mudah dipahami?
     → Nama yang membingungkan, fungsi terlalu panjang, logika yang tidak jelas
  6. Style: apakah sesuai dengan coding convention tim?
     → Ini paling rendah prioritasnya — banyak yang bisa ditangani oleh linter

// ✗ Reviewer yang salah prioritas
Menghabiskan 20 menit berkomentar soal naming convention
Melewatkan bug logic di fungsi yang lebih kompleks

// ✓ Reviewer yang benar prioritas
Langsung fokus ke logika yang paling kritis dulu
Baru ke hal-hal yang lebih minor setelah yang penting sudah dibahas

Berikan Konteks pada Setiap Komentar #

Komentar tanpa konteks tidak membantu author memahami mengapa perubahan diperlukan. Ini juga menghambat diskusi yang bermakna.

// ✗ Komentar tanpa konteks
"Ini salah"
"Gunakan pendekatan lain"
"Ini tidak bagus"

// ✓ Komentar dengan konteks yang jelas
"Pendekatan ini akan menyebabkan N+1 query ketika `orders` memiliki banyak item.
 Pertimbangkan menggunakan eager loading dengan JOIN atau preload:
 `db.Preload("Items").Find(&orders)`
 Ini akan mengurangi jumlah query dari O(n) menjadi O(1)."

"Fungsi ini melakukan terlalu banyak hal (fetch data, transform, validate, save).
 Sesuai SRP, pertimbangkan memisahkan ke beberapa fungsi yang lebih fokus.
 Ini juga akan membuat unit testing lebih mudah."

Bedakan Jenis Komentar #

Tidak semua komentar di code review memiliki tingkat kepentingan yang sama. Memberikan label pada komentar membantu author memahami mana yang harus ditindaklanjuti dan mana yang hanya saran.

// Konvensi pelabelan yang umum digunakan

[BLOCKING] — Harus diperbaiki sebelum PR bisa dimerge
"[BLOCKING] Ada potensi SQL injection di query ini karena input tidak di-sanitize."

[SUGGESTION] — Disarankan tapi tidak wajib
"[SUGGESTION] Pertimbangkan menggunakan konstanta untuk magic number ini
 agar lebih mudah dipahami."

[NITPICK] — Minor, tidak berdampak pada logic atau maintainability
"[NITPICK] Typo di komentar: 'recieve' → 'receive'"

[QUESTION] — Butuh klarifikasi dari author
"[QUESTION] Mengapa kita menggunakan timeout 30 detik di sini?
 Apakah ada konteks spesifik untuk angka ini?"

[FYI] — Informasi yang mungkin berguna, tidak butuh tindakan
"[FYI] Ada library baru yang bisa menyederhanakan ini, tapi tidak perlu diubah sekarang."

Berikan Review Tepat Waktu #

PR yang dibiarkan menunggu review terlalu lama adalah salah satu sumber frustrasi terbesar dalam proses engineering. Author kehilangan konteks karena sudah pindah ke task lain, dan PR berisiko menimbulkan merge conflict.

// SLA review yang umum digunakan
  ✓ PR normal (< 300 baris): review pertama dalam 4 jam kerja
  ✓ PR besar (> 300 baris): review pertama dalam 1 hari kerja
  ✓ PR urgent/hotfix: review dalam 1 jam kerja
  ✗ PR dibiarkan lebih dari 2 hari kerja tanpa respons apapun

Jika tidak bisa memberikan review penuh, respons minimal yang berguna:
  "Saya akan review PR ini besok pagi — ada deadline lain hari ini"
  "Saya sudah baca sepintas, ada satu hal yang ingin saya diskusikan dulu: [pertanyaan]"

Anti-Pattern PR dan Code Review yang Harus Dihindari #

// ✗ PR Monster — terlalu besar untuk direview dengan baik
PR dengan 2000+ baris perubahan, campuran feature, refactor, dan bug fix
→ Reviewer tidak bisa memberikan review berkualitas
→ Bug tersembunyi di balik volume perubahan
// ✓ Pecah menjadi PR kecil yang fokus pada satu tujuan

// ✗ LGTM tanpa membaca
Reviewer approve PR dalam 2 menit untuk PR 500 baris
→ Code review menjadi formalitas
→ Bug yang seharusnya bisa dicegah lolos ke production
// ✓ Jika tidak punya waktu review, katakan kapan bisa — jangan approve asal

// ✗ Komentar pasif-agresif atau menyerang personal
"Ini jelas salah. Apakah kamu pernah baca dokumentasinya?"
"Pendekatan ini menunjukkan kamu tidak paham cara Go bekerja"
// ✓ Fokus pada kode: "Pendekatan ini tidak sesuai dengan idiomatic Go karena..."

// ✗ PR tanpa deskripsi atau deskripsi yang tidak berguna
Title: "fix"
Description: (kosong)
// ✓ Deskripsi berisi latar belakang, perubahan utama, dampak, dan cara testing

// ✗ Komentar yang tidak jelas dan tidak actionable
"Refactor ini"
"Ini tidak bagus"
// ✓ Jelaskan mengapa dan tawarkan pendekatan alternatif

// ✗ Membuka PR tanpa CI lulus
Membuka PR dengan 5 test yang failing "nanti diperbaiki"
→ Reviewer membuang waktu untuk PR yang belum siap
// ✓ PR tidak boleh dibuka untuk review jika CI belum lulus

// ✗ Review yang hanya fokus style dan mengabaikan logic
Reviewer memberikan 10 komentar tentang naming dan formatting
tapi tidak membaca fungsi yang memiliki bug logic
// ✓ Prioritaskan correctness dan design di atas style

Checklist PR yang Siap Direview #

AUTHOR — Sebelum membuka PR untuk review:
  □ Satu PR, satu tujuan — tidak mencampur feature, refactor, dan bug fix
  □ Ukuran PR dalam batas yang bisa direview (< 300 baris jika memungkinkan)
  □ Self-review sudah dilakukan — kode sudah dibaca dari perspektif reviewer
  □ Deskripsi PR berisi: latar belakang, perubahan utama, dampak, cara testing
  □ CI sudah lulus (test, lint, build) — tidak ada yang failing
  □ Tidak ada debug code, console.log, atau TODO yang terlupakan
  □ Test sudah ditambahkan untuk logika baru
  □ Jika PR besar, ada panduan di deskripsi tentang urutan membaca file

REVIEWER — Selama review:
  □ Baca deskripsi PR sebelum membuka diff
  □ Pahami tujuan PR sebelum mulai memberikan komentar
  □ Prioritaskan: correctness → security → design → performance → readability → style
  □ Setiap komentar disertai konteks dan alasan
  □ Bedakan mana yang blocking, suggestion, nitpick, dan question
  □ Apresiasi hal-hal yang baik, bukan hanya mengkritik yang kurang
  □ Berikan review dalam SLA yang disepakati tim
  □ Akhiri dengan keputusan yang jelas: Approve, Request Changes, atau pertanyaan

TIM — Secara keseluruhan:
  □ Ada SLA review yang disepakati dan dipatuhi
  □ PR template tersedia dan digunakan secara konsisten
  □ CI wajib lulus sebelum PR bisa dimerge
  □ Tidak ada kode yang bisa bypass review (branch protection aktif)

Ringkasan #

  • PR adalah kontrak sosial, bukan formalitas — author berkomitmen bahwa kode siap dipertanggungjawabkan, reviewer berkomitmen memberikan feedback yang konstruktif dan tepat waktu.
  • Kode adalah aset tim — engineer yang memperlakukan kodenya sebagai milik pribadi akan defensif saat direview; engineer yang melihatnya sebagai aset bersama akan menyambut feedback.
  • Review kode, bukan orang — semua feedback diarahkan ke implementasi dan keputusan teknikal, bukan ke karakter atau kemampuan penulisnya.
  • Satu PR, satu tujuan — PR yang mencampur terlalu banyak tidak bisa direview dengan baik dan menyembunyikan bug.
  • Deskripsi PR sama pentingnya dengan kode — reviewer yang memiliki konteks penuh akan memberikan feedback yang jauh lebih relevan.
  • Prioritaskan correctness dan design di atas style — bug logic yang lolos code review jauh lebih berbahaya dari formatting yang tidak konsisten.
  • Berikan label pada komentar — bedakan mana blocking, suggestion, nitpick, dan question agar author bisa memprioritaskan responnya.
  • Review tepat waktu adalah bentuk respek — PR yang menunggu terlalu lama membuang konteks author dan menghambat delivery.
  • Bug yang ditemukan di code review jauh lebih murah dari bug yang ditemukan di production — ini adalah ROI paling jelas dari proses PR yang serius.

← Sebelumnya: Knowledge Sharing   Berikutnya: Anatomi PR →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact