- k10s adalah TUI Kubernetes yang sadar-GPU dan dibuat cepat lewat vibe-coding bersama Claude, tetapi setelah menambahkan fleet view, berbagai state layar mulai rusak
model.go membengkak menjadi satu Model tunggal sepanjang 1690 baris dengan Update() sepanjang 500 baris, memikul sekaligus state UI, klien, cache, navigation, dan view
- AI memang menambahkan fitur dengan cepat, tetapi juga memperbesar god object dan global key handler, sehingga setiap view baru menambah branch ke handler lama
- Data
[]string berbasis posisi dan mutasi langsung oleh background tea.Cmd dapat menimbulkan error kolom dan data race yang jelas
- k10s baru akan ditulis ulang dalam Rust, dan sebelum prompt pertama, interface, message type, ownership rule, serta scope akan dibakukan di CLAUDE.md
Latar belakang menulis ulang k10s
- k10s dimulai sebagai dashboard Kubernetes yang sadar-GPU, sebuah alat TUI yang dibuat agar operator klaster NVIDIA bisa langsung melihat informasi seperti utilisasi GPU, metrik DCGM, node idle, dan biaya
$32/hr
- Ditulis dengan Go dan Bubble Tea, alat ini dibuat lewat sesi vibe-coding bersama Claude selama sekitar 7 bulan, 234 commit, dan sekitar 30 akhir pekan
- Pada tahap awal, fitur dasar ala klon k9s seperti pods, nodes, deployments, services, command palette, live updates berbasis watch, dan Vim keybindings sudah berjalan hanya dalam sekitar 3 akhir pekan
- Fitur inti, yaitu GPU fleet view, adalah layar yang menampilkan alokasi GPU tiap node, utilisasi, metrik berbasis DCGM, suhu, daya, memori, dan status berbasis warna, dan Claude sekaligus menghasilkan struct
FleetView, pemfilteran tab GPU/CPU/All, hingga rendering allocation bars
- Setelah fleet view ditambahkan, saat kembali ke pods view dengan
:rs pods, tabel menjadi kosong, live updates berhenti, nodes view menampilkan stale data dari filter fleet view, dan fleet tab count juga menjadi salah
- Saat menelusuri masalahnya, penulis untuk pertama kalinya membaca seluruh
model.go sepanjang 1690 baris yang dibuat Claude, dan menemukan satu struct Model memuat sekaligus widget UI, Kubernetes client, state logs/describe/fleet, navigation history, cache, dan mouse handling
- Method
Update() berukuran 500 baris dan berupa fungsi dispatch msg.(type) dengan 110 branch switch/case
- AI memang bisa membuat fitur dengan cepat, tetapi jika terus diberi tugas tanpa batasan, arsitektur akan runtuh, dan rasa cepat itu tampak seperti keberhasilan sampai semuanya ambruk bersamaan
Lima prinsip yang muncul dari puing-puingnya
-
Prinsip 1: AI membuat fitur, tetapi tidak membuat arsitektur
- Claude cukup baik dalam membuat fitur individual seperti fleet view, log streaming, dan mouse support, tetapi tiap fitur diimplementasikan dalam konteks “dibuat agar jalan sekarang” dan tidak mempertimbangkan relasinya dengan fitur lain yang berbagi state yang sama
- Handler
resourcesLoadedMsg memuat kondisi seperti msg.gvr.Resource == k8s.ResourceNodes && m.fleetView != nil, sehingga logika khusus fleet view bercampur ke dalam jalur generic resource loading
- Setiap view baru yang butuh behavior khusus menambah branch ke handler yang sama, dan berbagai field harus dibersihkan manual agar data dari view sebelumnya tidak bocor ke view baru
- Di
model.go, cleanup manual seperti m.logLines = nil, m.allResources = nil, m.resources = nil tersebar di 9 tempat, dan jika satu saja terlewat, ghost data dari view sebelumnya akan tertinggal
- Alternatifnya adalah menulis sendiri lebih dulu interface, message type, dan ownership rule yang konkret sebelum menulis kode, lalu memasukkannya ke
CLAUDE.md sebagai architecture invariant
- Contoh aturannya: setiap view mengimplementasikan trait/interface
View, sebuah view tidak boleh mengakses state milik view lain, data async hanya masuk lewat variant AppMsg, dan struct App hanya bertanggung jawab atas navigation serta message dispatch
-
Prinsip 2: god object adalah keluaran default AI
- AI cenderung memilih struktur single struct yang memegang semuanya demi memenuhi prompt langsung dengan ceremony sesedikit mungkin
- Key handling juga tidak dipisah per view; satu tombol
s berfungsi sebagai autoscroll di logs view, shell di pods view, dan container shell di containers view
- Permintaan seperti “tambahkan shell support ke pods” diimplementasikan dengan menyisipkan branch di sekitar global key handler yang sudah ada
- Tombol
Enter juga bercabang untuk contexts view, namespaces view, logs view, dan generic drill-down logic dalam satu dispatch datar berdasarkan perbandingan string m.currentGVR.Resource
- Dalam satu file
model.go, m.currentGVR.Resource == dipakai lebih dari 20 kali sebagai semacam type discriminator, sehingga setiap penambahan view baru menuntut perubahan di beberapa handler
- Alternatifnya adalah memasukkan aturan ke
CLAUDE.md agar App/Model tidak diberi field state khusus view, setiap view dibuat sebagai struct terpisah, dan key binding ditempatkan pada keymap milik view yang aktif
- Harus ada guardrail seperti “menambahkan view harus berarti menambahkan file, dan jika perlu memodifikasi view yang ada, berhenti dan tanyakan dulu” agar AI tidak menambah branch lewat jalur terpendek
-
Prinsip 3: ilusi kecepatan memperlebar scope
- k10s semula adalah alat untuk audiens yang sempit, yaitu operator klaster training GPU, tetapi vibe-coding membuat fitur seperti pods, deployments, services, command palette, mouse support, contexts, dan namespaces terasa seperti “gratis”
- Akibatnya, arahnya meluas bukan lagi menjadi alat yang fokus pada GPU, melainkan TUI general-purpose untuk semua pengguna Kubernetes, pada dasarnya seperti membuat ulang k9s
keyMap yang datar mencampurkan banyak binding khusus view dalam satu struct, seperti Fullscreen, Autoscroll, ToggleTime, WrapText, CopyLogs, ToggleLineNums, Describe, YamlView, Edit, Shell, FilterLogs, FleetTabNext, FleetTabPrev
Autoscroll dan Shell sama-sama menggunakan s, dan karena dispatch memeriksa resource saat ini, semuanya memang “berfungsi”, tetapi keybinding menjadi mustahil dipahami secara lokal
- Kecepatan menulis kode tampak seperti sedang “shipping”, tetapi tiap fitur menambah biaya berupa satu branch lagi di dalam god object
- Alternatifnya adalah menegaskan scope boundary di
CLAUDE.md: k10s adalah alat untuk operator klaster GPU, view yang didukung dibatasi pada fleet, node-detail, gpu-detail, dan workload, dan tidak menambahkan generic resource view atau fitur yang menduplikasi k9s
- AI bisa memberi budget baris kode yang nyaris tak terbatas, tetapi complexity budget tetap terbatas, jadi scope harus ditolak sejak awal
-
Prinsip 4: data berbasis posisi adalah bom waktu
- k10s langsung meratakan resource dari Kubernetes API menjadi
type OrderedResourceFields []string
- Fungsi sort di fleet view memperlakukan
ra[3] sebagai Alloc, ra[2] sebagai Compute, dan ra[0] sebagai Name, sehingga identitas kolom hanya bergantung pada komentar dan urutan kolom di resource.views.json
- Jika satu kolom ditambahkan di antara Instance dan Compute dalam
resource.views.json, maka sort, conditional render, dan drill target yang merujuk ra[2] dan ra[3] bisa diam-diam menjadi salah
- Compiler tidak memahami makna
[]string, dan config JSON juga tidak bisa mengekspresikan sort behavior, conditional rendering, atau custom drill target, sehingga kode Go akhirnya meng-hardcode asumsi posisi
- AI cenderung memilih
[]string atau Vec<String> karena mudah langsung dimasukkan ke widget tabel, sedangkan typed struct butuh ceremony awal yang lebih besar sehingga tersisih dari jalur tercepat
- Alternatifnya adalah mempertahankan data terstruktur sebagai typed struct seperti
FleetNode dan PodInfo sampai tepat sebelum render, dan melakukan sort berdasarkan named field, bukan akses posisi seperti row[3]
- Contoh strukturnya adalah
FleetNode { name, instance_type, compute_class, alloc }, sehingga identitas kolom dinyatakan lewat type dan state yang mustahil seperti sort kolom yang salah tidak bisa dibentuk
- “Making impossible states impossible” adalah ungkapan yang dipakai di komunitas Elm/Rust untuk berarti merancang type agar invalid state tidak bisa dibentuk, alih-alih memeriksanya nanti saat runtime
-
Prinsip 5: AI tidak memiliki state transition
- Struktur Bubble Tea menempatkan perubahan state hanya di
Update() yang digerakkan oleh message, dan ini adalah intinya, tetapi k10s melanggar hal tersebut
- Handler
updateTableMsg mengembalikan closure tea.Cmd, dan di dalam closure itu field Model diubah lewat panggilan seperti m.updateColumns(m.viewWidth), m.updateTableData(), dan m.table.SetCursor(savedCursor)
- Bubble Tea menjalankan
tea.Cmd di goroutine terpisah, sehingga saat closure membaca dan menulis m.resources, m.table, dan m.viewWidth, View() di goroutine utama bisa saja sedang membaca field yang sama
- Tidak ada lock atau mutex, dan
<-m.updateTableChan hanya menunggu sinyal update, bukan mencegah View() membaca state yang baru setengah ditulis
- Struktur ini adalah data race yang jelas, dan biasanya tampak “berjalan” tetapi sesekali muncul sebagai tampilan yang rusak
- Alternatifnya adalah worker di background tidak memutasi UI state secara langsung, melainkan mengirim typed message lewat channel, dan main event loop menerima message itu lalu menerapkan mutasi state
- Aturan concurrency-nya adalah background task tidak boleh langsung mengubah UI state, melainkan mengirim hasil sebagai typed message, dan
render()/view() harus berupa pure function tanpa side effect, I/O, atau operasi channel
Aturan perlindungan yang akan dimasukkan ke CLAUDE.md dan agents.md
-
Invariant arsitektur
- Setiap view harus mengimplementasikan trait/interface
View, dan tidak boleh mengakses state milik view lain
- Semua data async harus masuk sebagai variant
AppMsg, dan background task tidak boleh memutasi field secara langsung
- Penambahan view baru tidak boleh menuntut modifikasi terhadap view yang sudah ada
- Struct
App harus menjadi thin router yang menangani navigation dan message dispatch
-
Aturan kepemilikan state
- Jangan menambahkan field state khusus view ke struct
App/Model
- Setiap view harus ada sebagai struct terpisah dan mendeklarasikan key binding-nya sendiri
- Aplikasi harus mendispatch key ke view yang aktif, dan keybinding baru harus ditambahkan ke keymap view terkait, bukan ke global handler
- Jika penambahan view menuntut modifikasi view yang sudah ada, berhenti dan minta konfirmasi
-
Scope
- k10s harus menjadi alat untuk operator klaster GPU, bukan untuk semua pengguna Kubernetes
- View yang didukung harus dibatasi pada fleet, node-detail, gpu-detail, dan workload
- Jangan menambahkan generic resource view seperti pods, deployments, atau services
- Jangan menambahkan fitur yang menyalin fungsi k9s
- Feature request yang tidak membantu operator job training GPU harus ditolak
-
Representasi data
- Jangan meratakan data terstruktur menjadi
[]string, Vec<String>, atau array berbasis posisi
- Data harus tetap mengalir sebagai typed struct sampai tepat sebelum render call
- Identitas kolom harus berasal dari nama field struct, bukan index array
- Fungsi sort harus bekerja pada typed field, bukan akses posisi seperti
row[3]
- Pembuatan string untuk display hanya boleh terjadi di dalam fungsi
render()/view()
-
Aturan konkurensi
- Background task seperti watcher, scraper, atau API call tidak boleh langsung memutasi UI state
- Background task harus mengirim hasil sebagai typed message ke channel
- Hanya main event loop yang boleh menerapkan mutasi state dari message yang diterima
render()/view() harus berupa pure function tanpa side effect, I/O, atau operasi channel
- Jika hasil kerja async perlu mengubah state, harus didefinisikan variant
AppMsg yang baru
Cara membangun ulang
- k10s akan ditulis ulang dalam Rust, bukan karena Rust lebih baik, tetapi karena terasa sebagai bahasa yang bisa dikendalikan secara langsung
- Dalam bahasa yang sudah cukup dikuasai, seseorang bisa merasakan ada yang salah bahkan sebelum dapat menjelaskannya dengan kata-kata, dan kepekaan ini tidak bisa digantikan oleh vibe-coding
- Saat AI menghasilkan kode yang tampak meyakinkan, diperlukan kemampuan untuk mendeteksi apakah itu sebenarnya sampah
- Pada versi baru, pekerjaan desain seperti concrete interface, message type, dan ownership rule akan lebih dulu dilakukan manusia secara manual sebelum penulisan kode
- Keputusan arsitektur yang sebelumnya salah ditentukan AI kini akan didokumentasikan sebelum prompt pertama dikirim
- Tautan ke TUI dan proyek yang ada: k10s Github dan K10S.DEV
Tambahan
- Bubble Tea adalah framework Go TUI berbasis The Elm Architecture, dan masalah arsitektur k10s berasal dari implementasi k10s, bukan dari Bubble Tea
- “Making impossible states impossible” adalah ungkapan di komunitas Elm/Rust yang berarti mencegah invalid state terbentuk lewat desain type, alih-alih memeriksanya saat runtime
- Seperti “em-dash” dalam tulisan AI, dalam coding AI bau “god-object” bisa tertinggal, dan vibe-coding dapat membuat implementasi terasa murah sehingga berujung pada hilangnya fokus dan bloat
1 komentar
Komentar Hacker News
Orang-orang yang bilang kode hasil generasi itu bagus pada dasarnya hanya orang-orang yang tidak membaca kode tersebut
Solusi mitigasi yang disarankan di tulisan itu juga sulit bertahan lama. Saat merancang sistem atau komponen, akan muncul invarian seperti “view tidak mengakses state milik view lain”, dan pada akhirnya pasti ada fitur yang harus ditambahkan yang berbenturan dengan kondisi itu
Pada titik itu biasanya pilihannya adalah membuang fiturnya, menumpuknya di atas invarian secara canggung dan tidak efisien, atau mengubah invarian itu sendiri. Pilihan ini bukan sekadar masalah konteks, melainkan masalah penilaian, dan model saat ini terlalu sering salah dalam penilaian ini
Jika batasan arsitektur dinyatakan secara eksplisit, agen justru membuat kode yang rumit dan mustahil dirawat dengan memaksa diri menyesuaikan ke batasan itu bahkan ketika seharusnya diubah. Kalau tidak dibaca lebih teliti daripada kode buatan manusia, pada akhirnya akan muncul “kode yang memakan dirinya sendiri” dan kita baru sadar saat semuanya sudah terlambat
Kuncinya adalah mengidentifikasi titik yang sulit bagi AI lalu membuatnya jadi mudah. Misalnya diperlukan konteks yang amat kecil, modularisasi dengan batas yang jelas, modul murni yang terpisah dari input/output, penyembunyian di balik interface, 100 tes yang selesai di bawah 1 detik, benchmark, dan sebagainya
AI bekerja baik ketika ada batasan dan konteks kecil. Jika itu tidak diberikan, performanya turun, dan tanggung jawabnya ada pada orang yang memakai alat tersebut
Tidak ada spesifikasi yang mampu bertahan terhadap kenyataan, dan sehebat apa pun investigasi serta desain awalnya, pada akhirnya ada invarian dalam spesifikasi yang akan terbukti salah
Ketika manusia menemui situasi ini saat pengembangan, ia bisa mundur selangkah dan memikirkan lagi apakah invarian itu salah serta apa dampaknya jika diubah. Sebaliknya, AI sering kali memaksakan solusi tambal sulam di bawah asumsi atau desain yang keliru, dan kurang punya wawasan untuk mengevaluasi ulang keseluruhan
Ini bisa membaik dengan alur kerja dan verifikasi yang baik, tetapi bukan area yang secara default ditangani dengan baik oleh alat seperti Claude Code, dan memang ada batasnya
Awalnya kami menetapkan prinsip yang kuat dan memindahkan beberapa penggunaan secara manual untuk membangun keyakinan. Migrasi totalnya sangat besar dan mahal sampai-sampai tertunda hampir 10 tahun, jadi kami ingin mempercepat dengan AI untuk menurunkan biaya
AI lumayan untuk 80% kasus yang mekanis dan sederhana. Sisa 20% memerlukan perubahan pada framework, dan kebanyakannya perubahan kecil seperti menambah field API, tetapi satu dua kasus memerlukan desain ulang konseptual
Backend pada suatu sistem bisa menghasilkan data tertentu dalam 99% kasus, tetapi ada beberapa kasus penting di mana secara logis data itu tidak bisa dibuat sehingga harus dilaporkan dari luar. Namun optimasi penting dibangun di atas asumsi bahwa “itu mustahil”
Alat AI tidak mendeteksi situasi ini dan menambahkan logika migrasi seolah semuanya akan bekerja benar. Berkat cara deploy kami, ini belum menjadi bug produksi, tetapi saat mengajukan pertanyaan yang benar ke tim partner kami menemukan kebutuhan serupa ada di tempat lain juga
Pada akhirnya masalah besar tidak terjadi karena ada satu orang yang benar-benar mendalami hal itu. Mungkin alat verifikasi dan model yang lebih pintar akan membuat migrasi seperti ini lebih mudah di masa depan, tetapi untuk saat ini kode generatif terlihat indah sekaligus rapuh sehingga harus terus diawasi dari dekat
Saya punya pola arsitektur yang agak aneh dan sudah dipakai sekitar dua bulan; setiap kali memakainya terasa sedikit tidak nyaman, dan baru tadi malam saya sadar bahwa itu bukan abstraksi yang bagus serta ada cara membaginya dengan lebih baik
Ketika saya membiarkan LLM menghasilkan kode, rasa tidak nyaman itu terasa jauh kurang jelas sehingga saya butuh lebih lama untuk menyadari masalah dan menemukan solusinya. Bagian pinggiran boleh saja digenerasi, tetapi untuk fitur inti saya masih harus menulis sebagian besar sendiri
Bahkan jika diekspresikan dalam bahasa formal yang presisi, LLM di bawah agen masih kurang mampu memahami mengapa invarian itu diperlukan dan mengapa itu penting. Mungkin nanti akan ada LLM yang bisa menghubungkan token dengan spesifikasi formal lalu menulis pembuktiannya, tetapi kode aneh yang lahir dari bagian prompt yang informal akan tetap muncul
Ini tidak bisa dicegah hanya dengan menambahkan batasan dan prompt ke daftar teknis atau spesifikasi. Anda bisa membuat jebakan yang lebih baik, tetapi makhluknya tetap lolos
Masalahnya adalah pembengkakan kode: menambah kode demi memuaskan prompt atau tugas. Sering kali kode yang lebih sedikit justru lebih baik, dan dibutuhkan orang yang bisa memprediksi apa yang diinginkan dan diharapkan orang lain. Generator itu bagus, tetapi harus dipakai dengan lebih terkendali, bukan seperti selang pemadam
Dulu saat Copilot mengisi otomatis satu baris, orang berkata “tetap saja kamu yang harus menulis seluruh fungsi”, lalu saat fungsi lengkap mereka berkata “logika di sekitar fungsi itu tetap harus kamu tulis”, lalu setelah logika itu selesai mereka berkata “fiturnya tetap harus kamu tulis”
Sekarang setelah fitur pun bisa selesai, mereka berkata “tetap saja arsitekturnya harus kamu yang tulis”. Saya tidak tahu apakah model ini bisa menyelesaikan arsitektur, tetapi menarik melihat ekspektasinya terus bergeser
Baik AI menyelesaikan satu baris, satu fungsi, satu fitur, atau satu tiket, kita tetap harus membaca dan memahami kodenya
Saya memakai AI terus-menerus dan memang makin membaik, tetapi saya tetap mereview setiap baris. Bahkan di level baris pun, sulit dibilang lebih baik daripada tab autocomplete tahun lalu; kadang sangat bagus, kadang sangat buruk
LLM sangat bagus untuk pengembangan perangkat lunak, tetapi hanya jika tidak dibiarkan menulis arsitektur. Modul, struct, enum dibuat sendiri, dan sebisa mungkin field serta variannya juga ditambahkan sendiri
Beri komentar dokumentasi pada setiap struct, enum, field, dan modul, lalu arahkan LLM ke modul dan struktur data itu agar ia mengisi isi fungsi yang dibutuhkan dan semacamnya
Walau sudah berkali-kali bilang “jangan pernah blocking di jalur kritis”, LLM tetap memasukkan blocking ke jalur kritis; walau dibilang “kalau melakukan X maka perlu tes tipe Y”, ia melakukan X tetapi lupa tesnya
Manusia juga tidak selalu mengikuti instruksi 100%, tetapi LLM lebih acak. Kesalahan manusia relatif lebih jarang berupa melakukan kebalikan persis dari yang diinginkan
LLM bisa melihat invarian penting dalam kode lalu membuat jalan memutar, menulis tes yang membuat kegagalan tampak seperti keberhasilan, mengatakan sudah melakukan sesuai permintaan, lalu menguburnya di dalam commit 5 ribu baris
Saya yakin LLM hebat dan merupakan masa depan, dan karena itu saya membuat bahasa https://GitHub.com/Cuzzo/clear untuk mereka. Kita harus melampaui masalah bahasa yang menuntut konteks global di tempat-tempat yang seharusnya tidak membutuhkannya agar lebih mudah bekerja bersama mereka
Ada keberhasilan juga, tetapi kadang begitu membuat frustrasi sampai saya bertanya-tanya apakah waras saya layak dikorbankan untuk ini
Bukan berarti arsitektur tidak penting, tetapi arsitektur yang cocok kemarin belum tentu masih cocok hari ini
Saat memakai agen coding, saya menetapkan beberapa aturan
Pertama, jika saya membiarkan agen menghasilkan kode, itu haruslah sesuatu yang saya benar-benar yakin bisa saya tulis sendiri dengan benar jika diberi waktu
Kedua, kalau tidak, saya tidak lanjut sampai saya memahami sepenuhnya hasil generasinya dan bisa mereproduksinya sendiri
Ketiga, jika saya melanggar aturan kedua, saya mungkin menciptakan utang kognitif, tetapi saya harus melunasinya penuh sebelum menyatakan proyek selesai
Makin besar utangnya, makin besar kemungkinan kualitas kode generasi berikutnya turun, dan rasanya seperti berbunga majemuk. Untuk proyek pribadi, cara ini menyenangkan, banyak mengajarkan saya, dan menyisakan codebase yang bisa saya pahami dengan nyaman
Harus ada titik keseimbangan agar tetap terhubung dengan keadaan codebase tanpa menjadi bottleneck tim
Claude adalah matematikawan tingkat doktor dan saya bukan, tetapi saya tahu persis sifat solusi yang saya inginkan serta cara menguji kebenarannya. Jadi saya mempertahankan solusi Claude alih-alih solusi saya yang sederhana dan naif, menuliskan fakta itu di pull request, dan semua orang menilai itu keputusan yang benar
Saya penasaran apakah kasus seperti ini layak jadi pengecualian. Jika AI nantinya jauh lebih baik daripada saya bukan hanya dalam matematika tingkat tinggi tetapi juga coding, pertanyaan yang lebih menarik adalah apakah saya akan berhenti total menulis kode sendiri, dengan asumsi saya tetap bisa menilai tesnya walaupun kemampuan menilai kode langsung memudar
Karena utang yang menumpuk itu tepatnya adalah kurangnya pemahaman terhadap kode, jadi istilah itu lebih presisi
Saya tidak tahu kenapa AI tiba-tiba harus diperlakukan berbeda
Pada akhirnya semuanya harus dinilai lewat risiko dan imbalan. Harus dipertimbangkan kerugiannya kalau salah, seberapa mungkin terdeteksi lewat tes dan review, serta apa keuntungannya jika berhasil. Hal yang sama berlaku untuk library dan layanan eksternal
Aturan finansial rumit dalam kontrak kripto yang tidak bisa diperbarui dan tanpa tes jelas tidak punya risiko yang sama dengan viewer untuk memvisualisasikan data log internal
Secara teori terdengar bagus, tetapi dalam praktik kita akan selalu mengambil jalan pintas mental tanpa sadar
Saat memperbaiki masalah di codebase yang asing, jika dibandingkan antara ketika saya melakukannya sendiri dan ketika saya merasa telah “sepenuhnya memahami” apa yang dilakukan agen, jumlah yang tersisa di kepala seminggu kemudian berbeda. Kalau dikerjakan sendiri, itu menjadi pengetahuan umum dan bagian pentingnya biasanya tertinggal; tetapi kalau saya mencoba menganggap hasil kerja agen itu sebagai milik saya, saat itu terasa seperti paham namun sangat cepat terlupakan
Karena itu saya menyimpulkan bahwa bantuan LLM dalam kasus seperti ini kebanyakan justru merugikan tujuan saya, bahkan tanpa mempertimbangkan kekhawatiran lain seperti waktu dan tekanan bisnis
Saya juga mengalami hal yang sama
Penipuannya berjalan seperti ini. Pada codebase yang bagus, AI bisa membuat banyak fitur, dan tampak lebih cepat, lebih aman, bahkan lebih akurat. Terutama di area yang kurang kita pahami, kesannya makin begitu
Seiring waktu codebase membesar, waktu untuk menelusuri makin panjang, dan tingkat kegagalan naik. Karena enggan mengakuinya, kita malah memaksa lebih keras, lalu baru berhenti ketika perubahan praktis sudah mustahil
Saat melihat lagi kodenya, kata spaghetti saja tidak cukup; kondisinya seperti Tembok Besar China
Pada akhirnya saya menghapus 75 ribu dari 140 ribu baris, dan merasa 3 bulan tenggelam dalam agentic coding itu terbuang sia-sia. Saya membuat fitur yang tak berguna, menambah bug, kehilangan model mental atas kode, melewatkan keputusan sulit yang hanya terlihat saat benar-benar berada di dalam kode, dan pada akhirnya juga gagal untuk pengguna
Bukan ingin menyindir, saya sungguh penasaran apa ekspektasi awalnya dan dari mana asalnya
LLM tampaknya diberi ekspektasi berbeda. Kalau Anda menyerahkan deskripsi fitur ringkas kepada “developer” acak yang hanya pernah ditemui online lalu menerima tumpukan implementasi setengah rusak, tidak ada yang akan kaget
Namun kadang orang berharap mukjizat dari mesin yang juga suka berhalusinasi panjang lebar, sesuatu yang bahkan tidak mereka harapkan dari manusia. Saya penasaran dari mana datangnya kepercayaan itu
Seperti kota besar yang merupakan kumpulan kota-kota kecil, ada peta, dan kita bisa memperbesar ke area lokal lalu bekerja dalam cakupan itu. Anda tidak perlu tahu semua detail New York hanya untuk minum secangkir kopi
Membangun arsitektur yang sehat dan mudah dirawat adalah tanggung jawab orang yang memakai alat. AI tidak menghalangi itu, dan kalau dipakai dengan benar justru bisa membantu
Misalnya dengan langsung memperlakukan kode hasil AI sebagai legacy code, memberi batas enkapsulasi yang kuat dan interface yang didefinisikan dengan baik, lalu mengintegrasikannya dalam alur kerja yang lebih manual
Ada spektrum mulai dari prompt sekali jalan sampai generasi kode inline, dan cara yang tepat berbeda tergantung masalah serta posisi di codebase
Generasi sekali jalan lebih cocok di tahap prototipe saat spesifikasi masih sering diulang, lalu setelah prototipe mantap turun ke generasi tingkat modul atau file agar lebih sistematis, sambil terus menjaga model mental yang layak di level itu
Kalau dibaca tetapi tidak dipahami, mestinya bisa meminta komentar terperinci pada tiap output; dan kalau tahu model makin kesulitan saat codebase membesar, maka makin tinggi kompleksitasnya justru output harus ditinjau lebih ketat
Caranya dengan membuat pulau-pulau kode berkualitas lebih tinggi, memakai AI untuk membantu merekonstruksi maksud developer dan aturan bisnis, lalu membuat seam dan unit test pada modul target
AI tidak harus selalu dipakai untuk menaikkan throughput; ia juga bisa menjadi alat eksplorasi dan refactoring yang fleksibel untuk membantu hand-coding atau implementasi agen di tahap berikutnya
Setiap kali melihat tulisan seperti ini saya jadi membandingkan kecepatan yang katanya didapat orang dari AI dengan kecepatan yang saya dapat hanya dengan coding manual
Kebetulan saya sudah 7 bulan mengerjakan proyek 3D MMO, dan saat ini sudah bisa dimainkan, orang-orang juga merasa seru, grafiknya lumayan, dan ratusan orang bisa masuk ke server dengan mudah. Arsitekturnya juga cukup bagus sehingga fitur mudah diperluas, dan saya rasa setelah sekitar 1 tahun pengembangan proyeknya bisa dirilis
Sementara penulis asli selama 7 bulan vibe coding bahkan belum bisa membuat TUI dasar. Kecepatan fitur mungkin terasa tinggi, tetapi untuk membuat UI dasar seperti itu kecepatannya sulit dipercaya lambatnya. Ada banyak library TUI yang bagus, dan ini jenis hal yang cukup dibuat manual dalam beberapa minggu dengan mengisi tabel dari data yang diperlukan
Saat memakai AI memang kuat sekali rasanya seperti maju cepat dalam jumlah besar, tetapi kenyataannya tampaknya sering jauh lebih lambat daripada coding manual. Data produktivitas juga sepertinya mendukung bahwa pengguna AI merasa lebih cepat tetapi output nyata mereka lebih sedikit
Penyedot waktu terbesar dalam kerja pengembangan perangkat lunak adalah rapat untuk menyelaraskan ekspektasi stakeholder dan solusi. Dari sudut pandang itu AI hampir tidak membantu, jadi kalau Anda membandingkan jam kerja dari usulan sampai masuk loop tes, hasilnya memang akan mengecewakan
Tetapi untuk pemecahan masalah, perbaikan bug, dan implementasi solusi yang sudah disetujui, rasanya sekarang setidaknya 10 kali lebih baik daripada dulu. Bukan hanya dari sisi waktu mentah, tetapi juga dalam kemampuan menafsirkan perilaku yang diamati dan menyelidiki masalah
Namun memang ada orang yang tidak bisa menghasilkan output AI yang akurat dan bernilai. Kalau Anda tahu persis apa yang diinginkan dan bagaimana menginginkannya, AI sangat membantu. Kalau saya menyuruhnya melakukan hal yang memang sudah akan saya lakukan, ia mengerjakannya lebih cepat. Tetapi kalau saya sendiri tidak tahu persis apa yang saya mau, AI justru merusak progres
Alasan karya buatan LLM yang ditunjukkan orang-orang tidak terlalu mengesankan adalah karena kebanyakan adalah hal-hal yang sebenarnya juga bisa dibuat manual dalam waktu sangat singkat
Saya juga tidak melihat ledakan perangkat lunak yang benar-benar mengesankan, dan itu tampaknya selaras dengan fakta bahwa LLM saat ini dipakai untuk menyelesaikan masalah yang sederhana, bukan yang penting
Hal lain yang kurang dibahas adalah kualitas kode
Codebase hasil vibe coding adalah contoh bagus bahwa LLM tidak terlalu unggul dalam menulis kode. Ia memperbaiki kesalahannya sendiri lalu langsung membuatnya lagi, dan pemakaian polanya juga tidak konsisten
Belakangan Claude juga kadang memilih gaya kode yang “menarik” tetapi tidak cocok dengan gaya codebase saat ini
Pengulangan seperti itu harus dicegah dengan bahasa ala “senior developer”
Bagian “sebelum menulis kode saya merancang sendiri interface konkret, jenis pesan, dan aturan ownership” itulah justru bagian sulit dari coding
Kalau arsitekturnya sudah ada, menulis kode jadi sangat mudah. Kalau Anda tidak menulis kodenya sendiri, akan lebih sulit menyadari bahwa Anda telah merancang API yang mengizinkan null padahal database tidak mengizinkannya, atau kalaupun mengizinkannya, Anda melewatkan masalah kecil lain
Saya tidak paham bagaimana setelah menulis artikel itu ia masih belum sadar bahwa masalahnya adalah AI. Bukan hanya karena ia menyerahkan arsitektur ke AI, tetapi juga karena ia tidak mengawasi dengan cermat semua hal yang dilakukan AI
AI adalah generator kode yang dipoles, dan semua yang dikerjakannya harus diperiksa. Bagian sulit dari rekayasa perangkat lunak bukanlah menulis kode, melainkan semua hal lain di sekitarnya
Developer yang menganggap coding itu sulit benar-benar menyukai AI coding, karena hal yang tadinya sulit kini menjadi mudah
Sebaliknya, bagi orang yang menganggap coding itu mudah, coding adalah masalah abstraksi, maintainability, dan skalabilitas. Yang sulit adalah meletakkan fondasi yang masuk akal agar perangkat lunak bisa tumbuh, dan begitu abstraksi yang tepat ditemukan, sisanya relatif mudah
Bagi orang seperti ini AI coding adalah alat yang berguna, tetapi bukan alat ajaib. Penulis asli menyadari keterbatasan AI, jadi ia termasuk kelompok kedua dan telah melihat bagian sulit yang tidak bisa dilakukan AI
Di satu sisi ada orang yang memakai tab autocomplete yang kuat atau chatbot di jendela samping sambil tetap mereview semuanya dengan jelas, dan di sisi lain ada editor baru yang dipromosikan Steve Yegge dengan koordinasi puluhan agen seolah sebagian besar kodenya tidak akan dibaca: https://steve-yegge.medium.com/welcome-to-gas-town-4f25ee16d...
Kelompok pertama masih memikirkan desain, interface, dan struktur data secara mendalam serta melakukan review ketat. Kelompok kedua lebih mengkhawatirkan karena tidak begitu
Mereka mengikuti pendekatan plan → red/green/refactor, dan rencananya sendiri tampak cukup meyakinkan serta berlandaskan karena menyerap habis dokumentasi dan diskusi forum
Masalahnya adalah begitu mulai bekerja, pasti muncul titik-titik di mana dokumentasi dan implementasi ternyata berbeda. Mungkin kombinasi alat itu belum pernah dipakai dengan cara tersebut, mungkin dokumentasinya usang, atau mungkin memang bug
Meski begitu, kalau tujuan proyek atau fiturnya cukup jelas dan bisa dijalankan serta dites secara lokal, agen bisa berputar-putar di jalan buntu arsitektur lalu akhirnya keluar. Mereka bahkan melihat dependensi dan kode library serta mengusulkan perbaikan upstream, mirip dengan yang saya lakukan dalam sesi debugging mendalam
Karena itu saya cukup puas dengan cara kerja memerintah dan mengawasi daripada mengerjakan tugas membosankan sendiri. Hanya saja banyak rekan tim saya secara default tidak menggali masalah arsitektur sedalam ini dan lebih memilih “eskalasi ke arsitek”, yang menurut saya dalam jangka panjang tidak baik
Jendela di mana seseorang masih bisa menjalankan dan memahami semuanya tampaknya menutup dengan cepat. Namun mungkin kita akan beradaptasi dengan membuat alat dan framework baru, seperti halnya kita tetap memakai compiler tanpa sepenuhnya memahami bagaimana ia mengubah kode menjadi machine code, atau tanpa sepenuhnya memahami branch prediction dan caching pada CPU modern
Dari sudut pandang orang yang belum terlalu berpengalaman dengan kode, saya justru belajar lebih banyak daripada sebelumnya dengan memeriksa hasilnya dan melihat mana yang benar dan salah
Karena itu saya juga tidak merasa ini akan segera membaik drastis. Saat orang bertanya “bagaimana output Claude bisa sebagus itu”, jawaban saya selalu “saya mengawasinya dengan cermat, menemukan masalah, lalu menyuruh Claude memperbaikinya”. Itu benar-benar semuanya, tetapi begitu mendengar itu pandangan mata mereka sudah mulai kosong
Ini seperti Google yang memudahkan pencarian informasi, tetapi tidak menghapus peran manusia dalam membedakan informasi yang baik dan buruk
Pikirkan dulu masalahnya, rancang struktur dan API-nya, baru setelah itu serahkan implementasinya ke AI
Judulnya memang “kembali menulis kode dengan tangan”, tetapi yang sebenarnya dilakukan adalah mengerjakan desain dengan tangan sebelum kodenya ditulis
Setelah itu kodenya tampaknya tetap dihasilkan oleh Claude
Yang lebih serius lagi, sulit dipahami bahwa selama 7 bulan ia mengira proyek vibe coding itu berjalan baik tanpa melihat source code yang dihasilkan, dan bahkan sudah membeli domain untuknya
Kalau ini side project dan Anda memeriksa perubahan secara bertahap dengan mengikuti diff, tidak mendalami kodenya juga tidak terlalu aneh. Memang gaya kerja yang berbeda, tetapi belum sampai tingkat gila
Rasanya seperti melihat para developer melakukan speedrun terhadap pelajaran manajemen proyek dan manajemen produk
Sekarang mereka mulai melihat bahwa spesifikasi itu berguna, dan membuat banyak kode yang salah tidak otomatis mempercepat proyek. Developer sering kesal karena rapat dan diskusi dianggap mengganggu waktu menulis kode, padahal proses itu sering ada justru untuk mencegah semua orang menulis lebih banyak hal yang salah
Mereka juga mulai sadar bahwa manajemen pekerjaan itu berguna, dan sekarang dengan makin seringnya pembicaraan bahwa semua desain harus dilakukan di awal, arahnya malah menuju waterfall
Berikutnya orang akan memberi nama pada prototyping, lalu muncul pembicaraan tentang fitur inkremental yang mengelola requirement lama dan baru sekaligus, dan akhirnya akan ada yang bilang pelanggan harus lebih terlibat
Perlu dilihat apa sebenarnya yang dilakukan project manager dan product manager. Mereka memimpin produk berupa kode, tetapi tidak diharapkan membaca kodenya, dan harus mencapai itu hanya lewat bahasa alami
Memangnya mereka pikir manusia tidak menulis hal yang rusak? Tidak pernah ada tim yang salah arah lalu membakar seminggu atau bahkan berbulan-bulan kerja? Sekarang dengan vibe coding Anda bisa mengalami semuanya dalam 30 menit. Sebagai mantan technical product manager, rasanya persis sama
Sebenarnya sepertinya bukan kembali menulis kode dengan tangan, jadi jarak antara judul dan kesimpulannya membingungkan