Back to all posts

1,3 juta baris, 630 PR per pekan: cara kami menjaga basis kode vibe-coded tetap sehat

1,3 juta baris, 630 PR per pekan: cara kami menjaga basis kode vibe-coded tetap sehat

Pada Juli 2026, Robert C. Martin menulis bahwa ia tidak lagi membaca kode yang dihasilkan oleh coding agent-nya.

Pernyataan itu menarik banyak perhatian. Namun sisa unggahannya lebih penting untuk memahami cara ia bekerja. Martin mengelilingi para agent dengan unit test, uji penerimaan Gherkin, prosedur QA, mutation testing, pemeriksaan cakupan, dan metrik kualitas. Kode memperoleh kepercayaannya dengan melewati sistem itu.

Beberapa bulan sebelumnya ia menyampaikan hal serupa. Alih-alih memeriksa implementasi, ia melihat cakupan pengujian, struktur dependensi, kompleksitas siklomatik, ukuran modul, dan hasil mutation testing. Ketika orang menafsirkannya sebagai menyerah dari peninjauan sama sekali, ia menjelaskan: "Saya meninjau banyak hal — hanya saja bukan kodenya."

Komentarnya menggambarkan masalah praktis dalam pengembangan perangkat lunak yang berat AI. Coding agent bisa menghasilkan perubahan lebih cepat daripada kemampuan orang membacanya. Begitu volume kode yang dihasilkan melampaui kapasitas peninjauan tim, pemeriksaan baris demi baris tidak bisa lagi menjadi satu-satunya sumber keyakinan.

Kami menghadapi masalah yang sama di vm0 selama delapan bulan terakhir. Sebagian besar implementasi di repositori kami ditulis oleh agent — vibe coding, dalam istilah populernya — sementara enam engineer tetap bertanggung jawab atas apa yang dilakukan kode itu di produksi.

Versi singkat

vm0 adalah basis kode vibe-coded: agent menulis sebagian besar implementasi, dan enam engineer bertanggung jawab atas apa yang dilakukannya di produksi. Setelah delapan bulan, repositori berisi 1.329.170 baris dan 630 pull request digabungkan dalam satu pekan. Lima mekanisme memikul beban kualitas yang tidak lagi bisa dipikul tinjauan baris demi baris sendirian.

  • Lingkungan yang konvergen. Engineer dan agent bekerja di dev container yang sama, dan setiap pull request bisa punya branch basis data sendiri. Perintah yang berhasil untuk agent juga berhasil untuk manusia.
  • Batasan yang bisa dieksekusi. TypeScript ketat, sekitar 135 modul kontrak API bertipe, Oxlint, ESLint, dan aturan arsitektur, dengan CI yang tidak menerima peringatan. Aturan yang bisa diperiksa mesin tidak diserahkan ke tinjauan.
  • Tes di batas modul. Testing trophy alih-alih piramida: tes integrasi lewat batas publik modul, PostgreSQL dan migrasi sungguhan, mock hanya di sistem eksternal. Kode tes sekitar 36 persen dari repositori.
  • Umpan balik yang lengkap. Agent menjalankan aplikasi dan basis data, menjalankan migrasi, dan mengemudikan browser sungguhan, lalu melaporkan perintah yang dijalankan, jalur yang diuji, dan tangkapan layar. Pull request median digabung sekitar 53 menit.
  • Pembersihan berkelanjutan. Knip membuang kode mati secara deterministik, workflow harian menyingkirkan AI slop yang tak bisa dinamai linter, dan pola yang cukup sering muncul dinaikkan menjadi aturan lint atau batasan tipe.

Apa arti sebenarnya vibe coding dan agentic coding

Vibe coding adalah meminta kode ke LLM, menjalankan hasilnya, meminta perubahan, dan tidak memperhatikan kode yang dihasilkan. Definisi Martin Fowler sengaja dibuat sempit, dan ia menyorot gagasan "lupakan bahwa kodenya ada". Ini cocok untuk prototipe, perangkat lunak sekali pakai, dan alat kecil dengan konsekuensi terbatas.

Agentic coding, yang Fowler sebut pemrograman agentik, adalah yang dilakukan tim ketika hasilnya akan dirawat. Agent membaca repositori, menyunting berkas, menjalankan tes, dan bekerja sendiri dalam periode panjang, sementara manusia tetap memegang struktur dan perilaku serta meninjau bukti dari setiap proses: hasil tes, sinyal kualitas, preview, dan perilaku produksi.

Bedanya bukan seberapa banyak kode yang ditulis model, melainkan ke mana perhatian manusia diarahkan.

Vibe codingAgentic coding
Otonomi agentPrompt, jalankan, prompt lagiMembaca repositori, menyunting, menguji, mengulang
Siapa yang membaca kodeTidak adaManusia membaca yang berisiko
Apa yang diverifikasiApakah hasilnya tampak benarTipe, kontrak, tes, preview, sinyal produksi
Paling cocok untukPrototipe dan alat sekali pakaiPerangkat lunak yang akan dirawat
Kegagalan khasKode yang tak dipahami siapa punVerifikasi terlalu lemah untuk volumenya

Agent yang menyunting repositori hanyalah satu cabang dari pergeseran yang lebih luas; sisi non-developer kami bahas terpisah.

Kami sering menyebut vm0 proyek vibe-coded karena istilah itu menjadi singkatan umum untuk perangkat lunak yang sebagian besar ditulis AI. Dalam istilah Fowler, ini lebih dekat ke agentic coding. Engineer kami mengetik lebih sedikit implementasi dibanding dulu, sambil tetap memegang arsitektur, biaya perawatan, dan perilaku produksi.

Seiring generasi kode makin cepat, makin banyak tanggung jawab itu berpindah ke lingkungan pengembangan, sistem tipe, suite tes, dan workflow perawatan otomatis.

Delapan bulan pertumbuhan di basis kode vibe-coded

Repositori vm0 dibuat pada November 2025. Pada saat laporan skala engineering mingguan kami yang terbaru, usianya sekitar delapan setengah bulan.

Isi repositori:

MetrikJumlah
Baris logis tidak kosong1.329.170
Baris produksi850.913
Baris pengujian478.257
Berkas sumber5.549
Berkas pengujian1.327
Paket44
Commit di branch utama14.005

Angka-angka ini berasal dari laporan skala engineering mingguan kami untuk pekan 20–26 Juli 2026, diukur langsung dari monorepo.

Kode pengujian menyumbang sekitar 36 persen dari basis kode yang diukur. Ini adalah porsi volume kode, bukan angka cakupan pengujian, tetapi memberi gambaran berapa banyak implementasi yang menumpuk di sekitar verifikasi.

Selama tiga pekan penuh terakhir, enam engineer membuat masing-masing 541, 640, dan 631 commit. Pada pekan 20–26 Juli, GitHub mencatat 630 pull request yang digabungkan. Enam engineer menulis 556 di antaranya, sementara otomatisasi rilis menulis 74 sisanya.

Waktu median dari membuka pull request hingga menggabungkannya sekitar 53 menit. Persentil ke-90 kira-kira 7,4 jam.

Pada laju perubahan seperti ini, peninjauan manusia tetap berguna tetapi tidak bisa memikul seluruh sistem kualitas. Kami memerlukan sinyal independen di beberapa titik dalam siklus hidup sebuah perubahan.

Pendekatan kami saat ini punya lima tema yang berulang: lingkungan yang konvergen, batasan yang bisa dieksekusi, pengujian yang berfokus pada batas, umpan balik yang lengkap, dan pembersihan yang berkelanjutan.

Mengonvergensikan lingkungan pengembangan dengan dev container

Banyak kegagalan yang sulit direproduksi berasal dari kondisi yang tidak pernah muncul dalam pull request.

Seorang developer bisa punya variabel lingkungan yang tak terdokumentasi, alat yang terpasang global, berkas konfigurasi lama, atau basis data yang sudah berjalan berbulan-bulan. Orang terbiasa dengan detail semacam itu. Agent biasanya tidak bisa melihatnya.

Kami perlahan berhenti memperlakukan mesin host sebagai lingkungan pengembangan standar. Engineer dan agent bekerja di dalam dev container. Image pengembangan berisi toolchain proyek, PostgreSQL, pgvector, Chromium, dan utilitas otomatisasi peramban.

CI berjalan di atas image toolchain berversi yang dibangun dari keluarga Dockerfile multi-tahap yang sama. Image pengembangan dan CI melayani tujuan berbeda, dan produksi punya bentuk deployment tersendiri. Sifat yang berguna adalah konvergensi: versi alat, dependensi, dan asumsi runtime bersifat eksplisit dan berversi.

Dari sini muncul ekspektasi yang lugas. Perintah yang dijalankan agent harus bisa direproduksi oleh engineer di dalam container pengembangan yang sama. Pemeriksaan yang lolos selama pengembangan harus berjalan di CI dengan toolchain yang sangat berdekatan.

Gagasan serupa kami terapkan pada data. Setiap pratinjau pull request bisa punya branch basis data sendiri serta menjalankan migrasi dan langkah seed yang sungguhan. Agent bisa membuat data, mengubahnya, dan mengulang pengujian destruktif tanpa meminjam basis data developer atau mewarisi kondisi dari pull request lain.

Perubahan lingkungan berjalan lewat repositori. Peningkatan alat, versi peramban, dan ekstensi basis data ditinjau serta disebarkan dengan cara yang sama seperti kode aplikasi.

Menjadikan standar engineering bisa dieksekusi lewat tipe dan aturan lint

Standar tertulis membantu orang memahami keputusan desain. Namun ia jauh kurang mampu menjamin setiap perubahan mengikuti keputusan itu, terutama selama sesi agent yang panjang.

Aturan yang stabil kami tanam ke dalam sistem tipe, linter, dan CI setiap kali aturannya bisa dinyatakan secara andal.

vm0 memakai pengaturan TypeScript yang ketat, termasuk strict dan noUncheckedIndexedAccess. Beberapa paket mengaktifkan pemeriksaan tambahan untuk nilai tak terpakai dan return implisit.

API memakai lapisan kontrak REST bertipe dan schema-first, dibangun dengan mesin tipe tRPC dan skema Zod. Drizzle menghubungkan akses basis data dengan tipe TypeScript. Pada saat peninjauan ini, repositori berisi sekitar 135 modul kontrak.

Pilihan-pilihan ini tidak menangkap keputusan produk yang keliru. Tetapi ia memunculkan pergeseran antarmuka lebih awal. Ketika sebuah field atau respons berubah, pemanggil terkait cenderung gagal saat analisis statis. Galat yang muncul biasanya cukup spesifik untuk dipakai agent pada iterasi berikutnya.

Linting menangani kelompok aturan kedua. Platform menjalankan Oxlint, pemeriksaan yang sadar tipe, dan ESLint, ditambah aturan arsitektur khusus proyek. CI tidak menerima peringatan. Peringatan yang boleh bertahan tanpa batas cenderung menjadi bising latar, dan bising latar mudah diabaikan baik oleh manusia maupun agent.

Ketika sebuah masalah berulang, kami mempertimbangkan di mana pemeriksaannya sebaiknya berada:

  1. Bisakah sistem tipe menyatakannya?
  2. Bisakah linter atau alat struktural mendeteksinya dengan akurat?
  3. Apakah ia menuntut penilaian semantik lintas repositori?

Dua yang pertama memberi umpan balik cepat dan deterministik pada setiap perubahan. Kelompok ketiga kami tangani lewat alur kerja berulang yang dijelaskan nanti di artikel ini.

Mempersempit pola rawan galat pada kode hasil AI

Beberapa fitur bahasa punya kegunaan yang sah sekaligus sering muncul dalam kode rapuh yang dihasilkan agent.

try/catch bisa mengaburkan batas galat. Ketika agent menemui kegagalan, menambahkan blok catch dan fallback adalah cara mudah menjaga jalur saat ini tetap hidup sambil kehilangan galat aslinya. Mencampur .then() dan .catch() Promise dengan async/await menyebarkan alur kendali ke beberapa gaya.

useEffect di React menimbulkan masalah serupa dalam pengelolaan state. Ia kerap dipakai untuk menyalin state, menyinkronkan dua sumber kebenaran, atau menyandikan ketergantungan urutan yang sulit terlihat dari model data.

Platform web inti membatasi pola-pola ini secara bawaan. Pengecualian yang beralasan boleh tetap ada, dengan penjelasan eksplisit di sampingnya.

Kode produksi platform web inti saat ini tidak mengandung useEffect sama sekali. Kami memakai ccstate dan pola bebas efek lain untuk memodelkan dependensi dan efek samping secara lebih eksplisit. Sejumlah kecil pemanggilan useEffect produksi masih ada di tempat lain dalam monorepo, terutama pada kode UI bersama dan desktop, jadi cakupan klaim ini penting.

Aturan-aturan ini tumbuh dari kegagalan yang berulang di repositori ini. Ketika sebuah pola berkali-kali menimbulkan masalah pemeliharaan yang sama, kami memindahkannya dari panduan peninjauan menjadi batasan yang bisa dieksekusi.

Menguji di batas modul: testing trophy, bukan piramida

vm0 tidak mengikuti piramida pengujian konvensional. Panduan pengujian kami menggambarkan testing trophy: analisis statis di dasar, pengujian integrasi sebagai lapisan dominan, dan sedikit pengujian end-to-end untuk perjalanan pengguna yang kritis.

Unit test relatif jarang. Kami memakainya secara selektif untuk logika yang sensitif terhadap keamanan, algoritme, dan state machine. Sebagian besar perilaku bisnis diuji melalui batas publik sebuah modul.

Pengujian API memanggil aplikasi yang sebenarnya melalui kontraknya. Data uji disiapkan lewat endpoint produksi bila memungkinkan, dan asersi dilakukan terhadap perilaku publik. Pengujian menghindari menjangkau langsung layanan internal atau mengubah tabel basis data, karena hal itu mengikatnya pada implementasi saat ini.

Infrastruktur internal tetap nyata di mana biayanya masuk akal:

  • PostgreSQL dan pgvector
  • migrasi basis data
  • sistem berkas
  • layanan internal
  • mock di batas sistem eksternal

Pengujian integrasi ini berjalan lebih lambat daripada unit test yang sangat terisolasi dan menuntut lingkungan yang lebih lengkap. Sebagai gantinya, ia mempersempit jarak antara "pengujian lolos" dan "aplikasi mampu melakukan operasi ini dengan basis data nyata".

Pengujian batas menyisakan ruang untuk refactor internal berskala besar. Agent bisa menata ulang modul, memecah layanan, atau mengubah lapisan akses data sementara perilaku publiknya tetap terlindungi.

Uncle Bob menyukai racikan berbeda, dengan penggunaan unit test, Gherkin, dan mutation testing yang berat. Prinsip yang sama-sama dianut adalah verifikasi independen. Proses yang menghasilkan kode tidak seharusnya menjadi satu-satunya sumber yang mengklaim kode itu bekerja.

Memberi coding agent umpan balik yang lengkap

Eksekusi coding agent kami di masa awal sering berakhir dengan laporan yang akrab: kode sudah diubah dan TypeScript lolos; silakan jalankan aplikasinya dan periksa halamannya.

Itu menyisakan separuh siklus pengembangan pada engineer. Seseorang tetap harus menyiapkan basis data, menjalankan layanan, membuka peramban, membuat data, mengamati kegagalan, dan menjelaskannya kembali kepada agent.

Kini agent punya cukup lingkungan pengembangan untuk mengerjakan lebih banyak bagian itu. Mereka bisa menjalankan aplikasi dan basis data, menjalankan migrasi, membuat data uji, mengunjungi pratinjau pull request, dan melakukan interaksi peramban yang sungguhan.

Verifikasi lewat peramban menangkap kelas masalah yang kurang tercakup oleh pemeriksaan tipe dan pengujian API: navigasi rusak, keadaan memuat yang tak kunjung selesai, galat izin yang hanya muncul dalam alur lengkap, dan regresi visual.

Di akhir eksekusi, agent melaporkan perintah yang dijalankannya, jalur yang diujinya, dan apa yang diamatinya. Untuk perubahan antarmuka, ia bisa menyertakan tangkapan layar. Engineer dapat memeriksa bukti itu sebelum memutuskan apakah perlu membuka pratinjau sendiri.

Tangkapan layar bukan pengujian dan tidak membuktikan tidak adanya cacat lain. Ia menurunkan biaya menyusun ulang konteks agent. Untuk perubahan antarmuka yang kecil, langkah yang dapat direproduksi dan satu tangkapan layar akhir jauh lebih berguna daripada pesan yang mengatakan perubahan itu "seharusnya sudah diperbaiki".

Kualitas kerja sebuah agent sangat bergantung pada umpan balik yang bisa ia peroleh tanpa menunggu orang.

Menjaga branch tetap pendek dengan trunk-based development

Pembuatan kode yang cepat bisa menghasilkan tumpukan branch yang besar.

Branch fitur berumur panjang menumpuk konflik merge, pekerjaan ganda, dan konteks yang basi. Seiring pull request membesar, peninjauan menjadi lebih sulit dan lambat. Kami memakai trunk-based development untuk menjaga branch tetap pendek dan berintegrasi terus-menerus di sekitar main.

Aturan branch utama kami mensyaratkan:

  • pull request untuk setiap perubahan
  • riwayat linear dan squash merge
  • sebuah merge queue
  • pemeriksaan Turbo, Rust, dan keamanan
  • tidak ada pengabaian rutin terhadap gate wajib

Otomatisasi menempuh jalur yang sama. Agent boleh membuat pull request, dan sebagian tugas pemeliharaan berisiko rendah boleh mengaktifkan merge otomatis, tetapi perubahannya tetap melewati CI dan merge queue.

Ukuran dan umur pull request membantu menjelaskan bagaimana 630 di antaranya bisa digabungkan dalam sepekan. Perubahan kecil membawa lebih sedikit konteks, lebih mudah diverifikasi, dan lebih kecil peluangnya berbenturan dengan pekerjaan produk atau perbaikan otomatis lain.

Knip sebagai garbage collection repositori: membuang kode mati

Pembuatan kode secara alami menambah berkas dan abstraksi. Penghapusan sering butuh prompt tersendiri.

Setelah refactor, berkas lama bisa tertinggal di repositori. Menghapus sebuah fitur bisa meninggalkan export, dependensi, dan entry point. Sisa-sisa ini jarang merusak pengujian, tetapi seiring waktu membuat basis kode lebih sulit ditelusuri.

Kami memakai Knip untuk menemukan berkas, export, dependensi, dan entry point yang tidak terpakai. TypeScript bisa memastikan kodenya valid; Knip bertanya apakah ia masih ikut serta dalam sistem.

Sisa itu punya biaya tambahan bagi coding agent. Repositori adalah salah satu sumber konteks terpenting bagi mereka. Sebuah helper usang atau implementasi yang ditinggalkan bisa tampak seperti pola yang disetujui bagi agent berikutnya yang membacanya.

Menghapus kode mati juga memperbaiki masukan yang tersedia untuk eksekusi berikutnya. Knip menangani bagian deterministik dari pekerjaan itu cukup cepat untuk menjadi pemeriksaan kualitas rutin.

Workflow berulang untuk membersihkan "AI slop"

Knip dan ESLint punya batas yang jelas. Banyak bentuk kemerosotan menuntut konteks proyek dan penilaian semantik.

Kami memakai "AI slop" sebagai label praktis untuk sisa ini: fallback yang tidak perlu, abstraksi ganda, pengujian yang memintas batas publik, atau cabang defensif untuk keadaan yang mustahil. Setiap kasus mungkin tampak tidak berbahaya. Secara agregat, ia membuat repositori lebih sulit dipahami dan memberi contoh buruk bagi agent di masa depan.

Beberapa alur kerja berulang di vm0 memindai pola-pola ini.

Pembersihan AI slop harian mencari sisa baru dan memilih sedikit perbaikan berkeyakinan tinggi dan berisiko rendah. Alur kerja lain memeriksa pengujian API yang menjangkau layanan internal, antipola React dan ccstate, serta utang teknis yang bisa ditangani dengan aman.

Setiap alur kerja menjaga perubahannya tetap sempit. Ia membuka pull request, lalu bersandar pada pemeriksaan tipe, aturan lint, pengujian, dan merge queue yang biasa. Pull request yang dikonfigurasi untuk merge otomatis pun tetap harus melewati gate yang sama.

Alur kerja pemeliharaan repositori otomatis dari pemindaian hingga CI dan merge, dengan perbaikan saat gagal

Alur kerja ini tidak berusaha melunasi seluruh utang teknis dalam satu jalan. Batch harian yang kecil lebih mudah diverifikasi dan tidak sekacau pembersihan besar tiap beberapa bulan.

Ketika sebuah alur kerja berulang cukup sering menemukan pola yang sama, kami mempertimbangkan memindahkan pemeriksaannya ke ESLint, Knip, atau sistem tipe. Alur kerja semantik berperan sebagai tempat mengamati dan mengasah aturan sebelum mengubahnya menjadi pemeriksaan deterministik yang lebih murah.

Workflow vm0 berulang ini berjalan sesuai jadwal.

Mengubah tes yang labil menjadi perbaikan otomatis

Kelompok alur kerja lain berangkat dari kegagalan GitHub Actions.

Ketika sebuah pengujian gagal di branch utama atau di merge queue, sebuah alur kerja membaca log, mencari bukti flakiness, dan menelaah percobaan ulang, waktu, serta faktor lingkungan. Jika buktinya mendukung perbaikan tertentu, ia memperbarui pengujian atau implementasi, membuka pull request, dan menjalankan kembali seluruh jalur CI.

Lolos pada percobaan ulang tidak membuat kegagalan aslinya tidak berbahaya. Tim yang bergantung pada tombol retry lambat laun kehilangan kepercayaan pada build merah. Begitu itu terjadi, pemeriksaan yang gagal menjadi bentuk lain dari bising latar.

Alur kerja perbaikan otomatis mengubah kegagalan yang sesekali muncul menjadi perubahan kode yang bisa dilacak. Diagnosis, tambalan, dan verifikasi tetap terlihat dalam pull request. Engineer bisa memeriksa perubahan yang berisiko lebih tinggi, sementara perbaikan sempit dengan bukti kuat boleh melaju lewat merge queue.

Sistem kualitas kami saat ini punya tiga lapisan besar:

TahapMekanismeKekhawatiran umum
Saat menulisTypeScript, kontrak, Drizzle, ESLintgalat tipe, pergeseran antarmuka, pola kode yang dikenal
Sebelum mergeKnip, pengujian integrasi, basis data nyata, pratinjau, merge queuekode mati, perilaku modul, hasil runtime yang lengkap
Setelah mergealur kerja vm0 terjadwal dan berbasis peristiwaAI slop, antipola semantik, pengujian flaky, pergeseran arsitektur

Lapisan-lapisan itu saling memberi makan. Masalah yang ditemukan alur kerja bisa menjadi aturan statis. Kegagalan yang ditemukan di CI atau produksi bisa menjadi pengujian dan panduan engineering baru.

Menjalankan agent terus-menerus ada biayanya, dan kami menulis terpisah tentang cara menekannya.

Ke mana perhatian manusia diarahkan saat meninjau kode hasil AI

Engineer vm0 masih membaca kode, terutama untuk perubahan arsitektur, pekerjaan yang sensitif terhadap keamanan, pembayaran, dan migrasi data. Kami tidak menjadikan "jangan pernah membaca kode" sebagai aturan tim.

Yang berubah adalah alokasi perhatian. Membaca kode adalah satu sinyal di antara kontrak, batas pengujian, perilaku pratinjau, tangkapan layar, metrik kualitas, dan diagnostik alur kerja.

Beberapa keputusan tetap menuntut penilaian yang berpengalaman:

  • apakah kebutuhannya sudah lengkap
  • di mana batas modul sebaiknya diletakkan
  • kegagalan mana yang bisa dipulihkan
  • seberapa besar dampak bisnis yang bisa ditimbulkan sebuah cacat
  • apakah model keamanannya memadai
  • pola kegagalan baru apa yang belum tercakup aturan saat ini

Engineer juga merawat lingkungan di sekitar para agent. Ketika sebuah masalah berulang, kami memutuskan apakah menambahkan batasan tipe, aturan lint, pengujian, atau alur kerja berulang. Sistem pengembangan itu sendiri telah menjadi artefak engineering yang penting.

Kode yang mudah dibaca tetap penting. Pembaca berikutnya bisa seorang engineer atau agent lain. Kode yang kusut memakan lebih banyak konteks, memperluas cakupan perubahan berikutnya, dan membuat verifikasi kurang bisa diandalkan.

Pergeseran serupa terjadi di sisi desain, saat design-as-code memindahkan keputusan visual ke repositori dan jalur review yang sama.

Keamanan dan perubahan yang tidak ikut dipercepat

Kecepatan tidak dibagi rata. vm0 punya daftar pendek perubahan yang berjalan dengan iramanya sendiri: pekerjaan sensitif keamanan, pembayaran, migrasi data, dan keputusan arsitektur. Seorang engineer membacanya baris demi baris, siapa pun atau apa pun penulisnya.

Risiko keamanan kode hasil AI, dari pengalaman kami, lebih jarang berupa kerentanan eksotis dan lebih sering berupa kode yang tampak masuk akal tetapi tak ada yang memilikinya. Kontrol yang menentukan justru yang biasa, asal diterapkan konsisten:

  • Tes unit, yang selebihnya jarang kami pakai, dipakai secara sengaja untuk logika sensitif keamanan, algoritma, dan mesin status.
  • Tes hanya melakukan mock di batas sistem eksternal. Infrastruktur internal tetap nyata, sehingga perubahan yang merusak kontrak internal gagal di CI, bukan di produksi.
  • Agent bekerja di dalam dev container terhadap branch basis data per pull request, bukan di mesin developer dan bukan di basis data bersama.
  • Merge queue dan check wajib tidak punya jalan pintas rutin, termasuk untuk pull request yang dibuka agent dan ditandai untuk merge otomatis.
  • try/catch dibatasi secara default, agar kegagalan tidak ditelan fallback yang ditambahkan agent demi menjaga jalur saat ini tetap berjalan.

Penanganan kredensial adalah masalah desain tersendiri dengan jawabannya sendiri: kami menjelaskan pola broker yang menjauhkan token dari jangkauan agent di artikel terpisah.

Tak satu pun dari ini membuat kode hasil AI otomatis aman. Semua itu mempersempit kumpulan perubahan yang keputusan manusianya adalah satu-satunya kontrol, dan membuat kumpulan itu eksplisit.

Apa yang tidak ditunjukkan angka-angka ini

Laporan mingguan menunjukkan skala repositori dan kecepatan pengiriman. Ia, dengan sendirinya, tidak menunjukkan keandalan di produksi.

Menilai pengaruhnya terhadap kualitas runtime menuntut ketersediaan, tingkat galat produksi, jumlah insiden, tingkat kegagalan perubahan, frekuensi rollback, dan waktu pemulihan rata-rata. CI yang hijau menggambarkan satu bagian dari proses pengiriman.

Kami terus menyusun ukuran-ukuran hasil itu. Praktik engineering menjelaskan bagaimana sebuah sistem mengelola risiko; data produksi menunjukkan seberapa baik pengelolaan itu bekerja.

Pertanyaan yang sering diajukan

Apa itu vibe coding? Vibe coding adalah meminta kode ke LLM, menjalankan hasilnya, meminta perubahan, dan tidak membaca kode yang dihasilkan. Definisi Fowler memang sempit: orangnya diminta "lupakan bahwa kodenya ada". Cocok untuk prototipe, perangkat lunak sekali pakai, dan alat dengan konsekuensi terbatas.

Apa itu agentic coding? Agentic coding adalah bentuk pengembangan berbantuan AI yang berjalan lebih lama, ketika agent membaca repositori, menyunting berkas, menjalankan tes, dan mengulang sendiri dalam periode panjang. Manusia tetap memegang arsitektur dan perilaku, serta meninjau bukti dari proses itu alih-alih setiap baris yang ditulis.

Apa beda vibe coding dan agentic coding? Perhatian, bukan kepengarangan. Pada vibe coding kode tidak pernah diperiksa. Pada agentic coding agent bekerja sendiri sementara engineer meninjau bukti di sekelilingnya: hasil tes, sinyal kualitas, preview, dan perilaku produksi. vm0 biasa disebut vibe-coded; dalam istilah Fowler, ini agentic coding.

Apa itu AI slop? AI slop adalah residu yang ditinggalkan kode hasil AI: fallback yang tidak perlu, abstraksi ganda, tes yang menembus batas publik, cabang defensif untuk keadaan mustahil. Satu per satu tampak tidak berbahaya. Digabung, semuanya membuat repositori lebih sulit dipahami dan memberi contoh buruk bagi agent berikutnya.

Bagaimana meninjau kode hasil AI pada 630 pull request per pekan? Bukan baris per baris. Di vm0, tinjauan manusia diarahkan ke tempat yang butuh pertimbangan: arsitektur, pekerjaan sensitif keamanan, pembayaran, migrasi data. Sisanya ditopang mekanisme: tipe ketat dan kontrak, tes integrasi di batas modul, basis data nyata pada preview tiap pull request, verifikasi browser, Knip, dan merge queue tanpa jalan pintas rutin.

Apa praktik terbaik vibe coding dalam skala besar? Lima hal bertahan di vm0 selama delapan bulan: menyatukan lingkungan pengembangan agar agent dan manusia menjalankan perintah yang sama; menjadikan standar bisa dieksekusi lewat tipe, linter, dan CI alih-alih dokumen; menguji di batas modul terhadap infrastruktur nyata; memberi agent umpan balik yang lengkap termasuk browser; dan membersihkan terus-menerus alih-alih sesekali besar-besaran.

Apa risiko keamanan kode hasil AI? Risiko yang umum bukan kerentanan eksotis, melainkan kode masuk akal yang tak ada pemiliknya. vm0 menahan pekerjaan sensitif keamanan, pembayaran, dan migrasi data pada tinjauan manusia, memakai tes unit secara sengaja untuk logika itu, menjaga infrastruktur internal tetap nyata dalam tes, membatasi pola seperti try/catch yang menelan kegagalan, dan tidak mengizinkan check wajib dilewati.

Apakah kode hasil AI menimbulkan utang teknis? Menimbulkan jenis tertentu: kode yang masih lolos kompilasi dan tes tetapi tidak lagi berperan dalam sistem, ditambah residu semantik yang tak bisa dinamai linter mana pun. Knip membersihkan bagian deterministik. Workflow berulang menangani sisanya dalam batch kecil harian, dan pola yang cukup sering muncul menjadi aturan lint atau batasan tipe.

Berapa banyak kode vm0 yang ditulis AI? Sebagian besar implementasinya. Pada pekan 20–26 Juli 2026, enam engineer menandatangani 556 dari 630 pull request yang digabungkan dan otomasi rilis sisanya, dan agent menulis sebagian besar kode di dalam pull request itu. Yang dipegang engineer adalah arsitektur, batasan, dan perilaku produksi.

Apa itu testing trophy, dan mengapa bukan piramida tes? Testing trophy menaruh analisis statis di dasar, tes integrasi sebagai lapisan dominan, dan sedikit tes end-to-end di puncak. vm0 memakainya karena tes yang ditulis lewat batas publik sebuah modul tetap melindungi perilaku saat agent menata ulang implementasi di bawahnya, hal yang tidak dilakukan lapisan tes unit yang besar.

Bagaimana menemukan kode mati di repositori hasil AI? Generasi kode menambah berkas dan abstraksi; menghapus biasanya perlu instruksi terpisah. vm0 menjalankan Knip sebagai pemeriksaan rutin untuk menemukan berkas, export, dependensi, dan entry point yang tak terpakai. TypeScript memastikan kode valid; Knip menanyakan apakah kode itu masih berperan dalam sistem, dan itulah pertanyaan yang penting untuk kode mati.

Apakah kode vibe-coded aman dijalankan di produksi? Itu bergantung pada apa yang memverifikasinya, bukan pada siapa yang mengetiknya. Sinyal yang kami syaratkan tidak berubah: tipe dan kontrak, tes lewat batas publik, infrastruktur nyata, dan pipeline yang harus hijau. Angka di artikel ini menggambarkan skala repositori dan kecepatan pengiriman; ketersediaan, tingkat galat, dan change-failure rate menjawab pertanyaan produksi, dan itu masih kami kumpulkan.

Delapan bulan berjalan

Delapan bulan terlalu dini untuk menyatakan sebuah metode final. Model, perkakas agent, dan repositori terus berubah, dan aturan serta alur kerja kami berubah bersamanya.

Satu pergeseran sudah jelas. Seiring pembuatan kode menjadi lebih cepat, lingkungan, batasan, pengujian, dan sistem umpan balik memikul lebih banyak beban kualitas. Engineer menghabiskan lebih sedikit waktu mengetik implementasi dan lebih banyak waktu mendefinisikan perilaku, merancang batas, dan memperbaiki verifikasi.

Basis kode vm0 akan terus tumbuh. Knip menyingkirkan sisa yang deterministik. Aturan statis menghalangi pola kegagalan yang sudah kami pahami. Pengujian integrasi melindungi perilaku modul. Alur kerja berulang menangani kemerosotan yang belum bisa kami nyatakan secara mekanis.

Kode tetap penting. Kini kami memakai lebih banyak bukti yang bisa dieksekusi mesin untuk memutuskan apakah sebuah perubahan layak masuk branch utama, dan apakah implementasinya sebaiknya tetap ada di repositori.

Stay in the loop

// Get the latest insights on AI teammates and collaboration.

SubscribeJoin Discord