Regresi — adalah bug yang muncul setelah melakukan perubahan pada kode, padahal fungsionalitas yang sama sebelumnya berfungsi dengan benar. Regresi berarti bahwa perubahan baru “merusak” apa yang sudah ditulis dan diuji sebelumnya. Ini adalah salah satu masalah yang paling umum dan berbahaya dalam pengembangan: saat memperbaiki satu bug, pengembang mungkin tanpa sadar merusak tiga fungsi lainnya. Menurut Capers Jones Software Engineering 2023, kepadatan rata-rata bug regresi adalah 1–3 per setiap 100 baris kode yang diubah. Kami membahas penyebab regresi, metode deteksinya, dan strategi pencegahannya.
Poin Utama
Regresi — adalah situasi ketika fungsionalitas yang berfungsi di versi sebelumnya berhenti berfungsi setelah perubahan dilakukan. Perubahan bisa apa saja: perbaikan bug, penambahan fitur baru, refactoring, pembaruan pustaka, atau bahkan perubahan konfigurasi. Regresi adalah musuh utama stabilitas: setiap perubahan berisiko merusak sesuatu yang sudah diperiksa dan dirilis.
Istilah ini berasal dari pengujian: pengujian regresi — adalah menjalankan kembali pengujian yang ada setelah setiap perubahan. Jika pengujian yang sebelumnya lulus gagal — berarti telah terjadi regresi. Dalam arti luas, regresi bukan hanya kegagalan pengujian, tetapi juga setiap penurunan perilaku yang diamati oleh pengguna atau QA. Menurut Tricentis State of Testing 2023, regresi mencakup 35–45% dari semua bug yang ditemukan di produksi.
Regresi berbeda dari bug biasa dalam konteks waktu: bug mungkin sudah ada sejak awal, sedangkan regresi selalu merupakan hasil dari suatu perubahan. Ini adalah perbedaan penting, karena mencari penyebab regresi dimulai dengan analisis perubahan: apa yang berubah antara “berfungsi” dan “berhenti berfungsi”. Git bisect — alat standar untuk menemukan commit yang menyebabkan regresi.
Regresi lokal — perubahan di modul A merusak fungsionalitas di modul A yang sama. Contoh: pengembang menulis ulang fungsi pengurutan, dan fungsi tersebut berhenti memproses array kosong dengan benar. Regresi lokal adalah yang paling mudah dideteksi dan diperbaiki, karena sebab dan akibat berdekatan.
Regresi jarak jauh — perubahan di modul A merusak fungsionalitas di modul B, yang tidak terhubung langsung melalui kode, tetapi terhubung melalui data atau waktu. Contoh: perubahan skema basis data di modul “Pengguna” merusak laporan di modul “Analitik” yang menggunakan tabel yang sama. Regresi jarak jauh adalah yang paling berbahaya: pengembang tidak curiga bahwa perubahannya akan memengaruhi modul lain.
Regresi efek samping — perubahan efek samping (logging, caching, pengiriman notifikasi) merusak perilaku yang diharapkan. Contoh: pengembang menambahkan caching untuk mempercepat kerja, tetapi karena cache yang usang, pengguna melihat data yang kedaluwarsa. Regresi efek samping sulit ditangkap dengan pengujian otomatis, karena efek samping sering tidak tercakup oleh pengujian.
Regresi kinerja — kode terus berfungsi dengan benar secara fungsional, tetapi lebih lambat dari sebelumnya. Contoh: algoritma enkripsi baru memberikan hasil yang sama, tetapi waktu eksekusi meningkat dari 2 ms menjadi 200 ms. Regresi kinerja tidak terdeteksi oleh pengujian unit biasa — diperlukan tolok ukur dan pembuatan profil.
| Jenis regresi | Contoh | Metode deteksi |
|---|---|---|
| Lokal | Pengurutan rusak | Pengujian unit |
| Jarak jauh | Perubahan skema DB | Pengujian integrasi |
| Efek samping | Cache usang | Pengujian E2E |
| Kinerja | Respons lambat | Tolok ukur |
Penyebab pertama — keterkaitan kode (coupling). Semakin kuat modul bergantung satu sama lain, semakin tinggi kemungkinan bahwa perubahan di satu modul akan menyebabkan regresi di modul lain. Antipola klasik: God Object (objek yang melakukan segalanya), Shotgun Surgery (perubahan satu memerlukan perbaikan di puluhan tempat), Circular Dependency. Mengurangi coupling — tugas arsitektur: prinsip SOLID, Dependency Injection, arsitektur heksagonal.
Penyebab kedua — kurangnya pengujian untuk fungsionalitas yang diubah. Jika kode tidak tercakup oleh pengujian, pengembang hanya mengetahui tentang regresi dari QA atau pengguna. Menurut Google Testing Blog, proyek dengan cakupan pengujian >75% memiliki 5 kali lebih sedikit regresi dibandingkan proyek dengan cakupan <25%. TDD (Test-Driven Development) menjamin bahwa pengujian ditulis sebelum kode, bukan “ketika ada waktu”.
Penyebab ketiga — faktor manusia. Pengembang tidak mengetahui keberadaan fungsionalitas yang berdekatan, tidak memahami semua dependensi, atau hanya terburu-buru. Penyebab — berbagi pengetahuan tentang basis kode yang tidak memadai. Solusi: code review dengan partisipasi pengembang dari modul lain, pair programming, dokumentasi arsitektur. Bus factor proyek berbanding terbalik dengan jumlah keputusan arsitektur yang didokumentasikan.
Pengujian regresi — adalah proses menjalankan kembali pengujian yang ada setelah setiap perubahan untuk memeriksa apakah fungsionalitas lama tidak rusak. Ini adalah satu-satunya cara untuk menjamin bahwa perubahan baru tidak mengganggu kinerja kode yang ada. Tanpa pengujian regresi, setiap rilis adalah lotere: pengembang berharap tidak merusak apa pun, tetapi tidak dapat memastikannya.
Pengujian regresi manual — pendekatan termahal dan paling tidak efisien. Seiring pertumbuhan proyek, jumlah skenario pengujian regresi meningkat secara linear, dan waktu untuk menjalankannya secara manual — secara eksponensial. Setelah 2–3 tahun pengembangan, menjalankan regresi secara manual dapat memakan waktu 2–3 minggu, yang membuat rilis sering menjadi tidak mungkin. Satu-satunya jalan keluar adalah otomatisasi.
Pengujian regresi otomatis dibagi menjadi beberapa tingkatan menurut piramida pengujian:
Menurut Google Testing Blog, rasio optimal: 70% pengujian unit, 20% integrasi, 10% E2E. Penyimpangan dari rasio ini mengurangi efektivitas pengujian regresi: kelebihan pengujian E2E memperlambat pipeline, kekurangan pengujian unit membuat microbug tidak terdeteksi.
Strategi pertama — Full Regression. Semua pengujian proyek dijalankan. Pendekatan paling andal, tetapi juga paling lambat. Cocok untuk proyek kecil (hingga 10.000 pengujian, waktu eksekusi <30 menit). Untuk proyek besar, regresi penuh dapat memakan waktu berjam-jam, yang membuat pipeline CI/CD tidak praktis.
Strategi kedua — Selective Regression. Hanya pengujian yang terkait dengan kode yang diubah yang dijalankan. Untuk menentukan hubungan, digunakan grafik dependensi kode. Alat: Bazel (Google), Nx (JavaScript), sbt (Scala). Selective regression menghemat 60–80% waktu eksekusi, tetapi memerlukan pembuatan grafik dependensi yang akurat — kesalahan menyebabkan regresi terlewatkan.
Strategi ketiga — Prioritized Regression. Semua pengujian diperingkat berdasarkan prioritas: critical path (skenario pengguna terpenting), high risk (kode dengan riwayat bug), changed code (kode yang terpengaruh oleh perubahan). Pertama, pengujian dengan prioritas tertinggi dijalankan — jika lulus, pengembang mendapatkan umpan balik cepat. Eksekusi terbatas waktu: dalam 10 menit pengujian kritis diperiksa, sisanya — di latar belakang.
Langkah pertama dan terpenting — budaya menulis pengujian. Setiap perubahan harus disertai dengan pengujian yang memeriksa bahwa perubahan berfungsi dan pengujian yang memeriksa bahwa tidak ada yang rusak. TDD (Test-Driven Development) memberikan hasil terbaik: pengembang pertama-tama menulis pengujian yang gagal, lalu kode yang membuatnya lulus. Ini menjamin bahwa pengujian ada sebelum kode.
Langkah kedua — pipeline CI/CD dengan eksekusi pengujian wajib. Pull request tidak dapat digabungkan sampai semua pengujian lulus. Pengujian tidak dapat “dilewati” karena urgensi — perubahan mendesak melalui rangkaian pengujian yang dipercepat tetapi wajib. Menurut Google DevOps Research, tim dengan CI/CD wajib memiliki 3 kali lebih sedikit regresi di produksi.
Langkah ketiga — monitoring di produksi. Bahkan pengujian terbaik pun tidak menjamin perlindungan 100% terhadap regresi. Alat observability (Sentry, Datadog, New Relic) harus melacak metrik utama setelah setiap penerapan: tingkat kesalahan, latensi, throughput. Pengembalian otomatis (rollback) saat melebihi ambang batas — bantalan pengaman jika regresi tetap masuk ke produksi.
Langkah keempat — code review dengan pemikiran regresi. Peninjau harus mengajukan pertanyaan: “Modul lain mana yang mungkin rusak karena perubahan ini?”. Tidak cukup memeriksa bahwa kode itu benar — perlu memeriksa bahwa kode tidak akan mengganggu fungsionalitas yang berdekatan. Daftar periksa untuk code review harus menyertakan poin “pemeriksaan regresi di modul yang berdekatan”.
Pertanyaan yang Sering Diajukan
Regresi — adalah bug yang sebelumnya tidak ada. Bug biasa mungkin sudah ada sejak fitur dibuat. Regresi selalu terkait dengan perubahan tertentu — ini memungkinkan penggunaan git bisect untuk menemukan penyebabnya.
Gunakan git bisect: tunjukkan commit di mana semuanya berfungsi dan commit di mana semuanya rusak. Git akan melakukan pencarian biner dalam riwayat dan menemukan commit yang menyebabkan regresi. Ini berfungsi bahkan untuk proyek besar dengan ribuan commit.
Tidak ada angka pasti, tetapi ada aturan empiris: cakupan alur pengguna utama harus 100%, cakupan semua fungsi — setidaknya 70%. Kualitas lebih penting daripada kuantitas: pengujian yang memeriksa edge case lebih berharga daripada sepuluh pengujian pada happy path.
Ya, dan ini disebut infrastructure regression. Pembaruan sistem operasi, versi basis data, sertifikat SSL, atau konfigurasi server web dapat merusak kode yang berfungsi. IaC (Infrastructure as Code) dan pengujian infrastruktur (Test Kitchen, Terratest) membantu menangkap regresi semacam ini.
Mulailah dengan satu alur pengguna kritis. Tulis pengujian otomatis untuk skenario terpenting (login, melakukan pemesanan). Tunjukkan di demo bagaimana pengujian menangkap regresi. Ketika tim melihat manfaatnya — terapkan pengujian secara bertahap, perluas cakupannya.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga