Skip to content

Spec QA sudah jadi jam 9 pagi, lalu owner bilang: kurang lebar

Adityo Guni Waluyo

Spesifikasi QA backfill lahir jam 9 pagi, lalu dilebarkan owner beberapa menit kemudian: kunci perilaku lama, ukur baseline, retest satu irisan penuh.

Ringkasan

Awalnya gue kira cukup tambah unit test buat validator KotaPortal biar validasi aman. Ternyata owner minta ukur baseline dulu pake go test cover sama Vitest baru cek irisan full dari DB sampai halaman. Akhirnya spec jadi empat langkah: kunci perilaku lama, ukur baseline, retest vertical slice, dan lempar semua temuan ke Owner Decision List.

Jam sembilan lewat sedikit, saya baru push docs/superpowers/specs/2026-10-09-qa-backfill-unit-slice-design.md untuk KotaPortal. Isinya rapi. Fokusnya satu: tutup lubang data-validation di level unit. Validasi di KotaPortal memang belum diuji sedalam itu, jadi saya pikir wajar kalau perbaikan dimulai dari validator dan service paling bawah.

Beberapa menit kemudian chat masuk. Satu pesan: jangan berhenti di unit. Kalau memang mau backfill QA, uji ulang satu irisan vertikal penuh, dari DB sampai halaman. Spesifikasi yang baru saja jadi itu mendadak terasa terlalu sempit.

Tebakan awal saya: tambah unit test validasi saja cukup

Tebakan saya pagi itu sederhana. Banyak bug validasi lahir dari aturan yang tidak eksplisit, jadi solusinya adalah menambah unit test untuk setiap validator. Saya sudah bayangin daftar validator yang perlu di-cover, kejar angka coverage, selesai.

Masalahnya, asumsi ini menganggap coverage sama dengan kebenaran. Padahal tidak. Line coverage hanya bilang sebuah baris pernah dieksekusi oleh test, bahkan kalau test itu tidak punya assertion sama sekali [1]. Sebuah studi 2014 yang dikutip di halaman yang sama mencatat 58% kegagalan katastropik berawal dari kesalahan trivial yang sebenarnya bisa ketahuan lewat statement coverage [1]. Angka itu mengingatkan saya: coverage tinggi tanpa assertion tetap bisa menipu.

Ada satu bagian yang saya lewatkan. Data-validation itu bukan cuma cek syntax. Definisi yang dipakai OWASP jelas: validasi harus mencakup syntax, semantics, dan konsistensi antar field, dan prinsipnya adalah definisikan apa yang diterima aplikasi lalu tolak sisanya [2]. Kalau saya hanya mengejar unit validator, saya tidak menjawab konsistensi lintas field dan kontrak API yang sudah terlanjur dipakai frontend.

Saya juga lupa satu hal. Baseline KotaPortal sendiri belum jujur. Spec mencatat persentase per-package yang ada sekarang menyesatkan karena sebagian besar suite hidup di tier integrasi. Tanpa pengukuran ulang, angka apa pun hanya tebakan.

Arahan yang datang beberapa menit kemudian

Arahan owner membalik urutan kerja. Bukan "tambah test dulu, ukur belakangan", tapi "ukur dulu, baru klaim". Itu yang jadi Fase 0 di spec revisi.

Fase 0 itu tabel baseline, bukan narasi. Untuk Go, saya harus menjalankan instrumentasi bawaan lewat go test -count=1 -cover -tags=integration ./internal/... -p 1 dan opsi -coverprofile yang memang disediakan toolchain [4]. Untuk frontend, Vitest yang jadi patokan, dengan pilihan provider v8 atau istanbul yang beda cara instrumentasinya [3]. Di atas itu ada run_page.sh <modul> per modul dan smoke runner untuk melihat halaman benar-benar bisa dibuka. Baru setelah tabel ini ada, saya boleh bicara soal gap.

Perubahan ini masuk akal karena memaksa satu disiplin: ukur dengan tooling yang sama sebelum mengubah apa pun. Tanpa itu, saya cuma memindahkan rasa tidak nyaman menjadi angka yang terlihat bagus.

Spec yang akhirnya saya tulis jadi empat langkah

Spec final tidak lagi berjudul "unit-level" saja. Strukturnya saya bagi jadi Konteks, Tujuan, Fase 0 baseline, checklist per slice, dan Owner Decision List. Empat gerakannya saling mengunci.

Pertama, characterization lock. Dengan legacy code, source code adalah kebenaran, bahkan ketika di dalamnya ada bug [1]. Spec menulis eksplisit: "Cover the code with characterization tests." [1] Artinya perilaku sekarang dianggap benar dulu sampai owner memutuskan lain. Tidak ada perubahan perilaku diam-diam lewat test baru.

Kedua, Fase 0 baseline seperti di atas. Tidak ada target persen presisi di artikel ini karena angka internal tidak punya URL publik untuk dirujuk, jadi saya tulis kualitatif saja: coverage service dan validator masih tipis, integrasi mendominasi. Semua angka yang bisa diverifikasi tetap saya tautkan ke sumber terbuka, bukan ke dokumen privat.

Ketiga, uji ulang satu irisan penuh, bukan satu layer. Alurnya DB → API → kontrak OpenAPI → FE → halaman. Di tengahnya ada npx @redocly/cli lint biar deskripsi OpenAPI valid secara mesin [5] dan npm run gen:api untuk menjaga sinkronisasi kontrak. Lalu run_page.sh <modul> dan smoke runner dipakai melihat apakah halaman tidak cuma ter-render, tapi juga bisa diakses lewat routing yang benar. Di sinilah dua kriteria tambahan masuk: routing/link integrity biar navigasi tidak putus di tengah jalan, dan quality gate khusus admin dashboard — CRUD, search/filter, serta state loading/empty/error yang selama ini luput dari unit test.

Keempat, semua temuan tidak langsung jadi fix. Temuan masuk ke Owner Decision List. Kalau sebuah test tidak bisa diandalkan untuk memblokir merge atau rilis, lebih baik diperbaiki atau dihapus saja [6]. Dan karena E2E itu mahal perawatannya, porsinya memang harus dijaga minimal [7]. Urutan yang dianjurkan GitLab juga jelas: mulai dari level paling bawah, Unit → Integration → System → E2E [6]. Spec mengikuti itu, tapi tidak berhenti di unit.

Pendapat saya tegas di sini. Angka coverage tanpa retest irisan adalah metrik penghibur. Spec ini yang mengubah "kita harus nambah test" menjadi rencana yang bisa dieksekusi dan diaudit: ada baseline yang terukur, ada checklist per slice yang bisa dicentang, ada gerbang kontrak yang bisa dijalankan ulang dengan perintah yang sama besok pagi. Saya menutup spec dengan memindahkan semua ambiguitas ke Owner Decision List, bukan ke kode.

Sumber

[1] https://tdd.mooc.fi/4-legacy-code

[2] https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html

[3] https://vitest.dev/guide/coverage

[4] https://pkg.go.dev/cmd/cover

[5] https://redocly.com/docs/cli/commands/lint

[6] https://docs.gitlab.com/development/testing_guide/testing_strategy

[7] https://www.martinfowler.com/articles/practical-test-pyramid.html

Artikel terkait