Cara Merusak Proyek dengan Terlalu Banyak Berpikir, Perluasan Cakupan, dan diff Struktural
(kevinlynagh.com)- Proyek mudah terbelah antara alur langsung membuat lalu menyelesaikan dan alur ketika riset serta perancangan membesar hingga kehilangan masalah semula; untuk kemajuan nyata, sering kali langsung mencobanya justru lebih unggul
- Bahkan saat membuat pencarian fuzzy path untuk Emacs, fitur tambahan dari library yang bagus melahirkan kebutuhan baru sehingga desain membengkak; pada akhirnya seluruh kode fitur anchor yang sebenarnya tidak diperlukan dibuang, dan ini kembali menegaskan YAGNI
- Dalam diff kode, perbandingan per baris tidak benar-benar menangkap struktur tingkat atas seperti fungsi atau tipe, dan bahkan alat berbasis treesitter pun bisa menjadi sulit dibaca bila pencocokan entitas meleset sehingga perubahan ditampilkan sebagai penghapusan dan penambahan yang panjang
- Arah yang dibutuhkan adalah lebih dulu membuat alat dengan cakupan minimum yang cocok untuk review per giliran atas output LLM; dimulai dari ekstraksi entitas Rust dan pencocokan sederhana, dengan prioritas pada workflow untuk cepat melihat ringkasan perubahan tingkat tinggi
Terlalu Banyak Berpikir dan Perluasan Cakupan
- Proyek mudah terbelah antara alur langsung membuat lalu selesai dan alur ketika menggali contoh terdahulu membuat cakupan membesar hingga pada akhirnya gagal menyelesaikan masalah awal
- Rak dapur yang dibuat pada akhir pekan diselesaikan dalam satu akhir pekan: desain diputuskan sambil minum kopi, hanger cetak 3D direvisi beberapa kali, lalu sisa material dan cat dipakai untuk menyelesaikannya
- CAD untuk hanger bin Ikea dipublikasikan di OnShape CAD
- Materialnya memakai ulang sisa dari meja kerja, dan sudut-sudutnya dihaluskan kira-kira dengan palm sander
- Untuk rak ini, kriteria sukses utamanya bukan membuat benda yang pas secara presisi untuk dapur, melainkan menikmati pekerjaan kayu bersama teman, sehingga kebutuhan untuk terlalu memikirkan kriteria detail pun berkurang
- Sebaliknya, saat mencari alat diff struktural, hasil dari difftastic terasa kurang memuaskan sehingga 4 jam dihabiskan untuk meneliti alat dan workflow terkait, sebelum akhirnya kembali ke kriteria awal: workflow diff yang lebih baik untuk dipakai di Emacs
- Minat lama seperti antarmuka prototyping hardware, bahasa yang mencampur Clojure dan Rust, atau bahasa untuk CAD telah memakan ratusan jam riset latar belakang dan prototipe kecil, tetapi belum menghasilkan sesuatu yang langsung menyelesaikan motivasi awalnya
- Antarmuka prototyping hardware berlanjut dari September 2023, desain bahasa dari November 2023, dan ide terkait CAD ke constraints, bidirectional editing, serta other dubious ideas
- Dalam proyek bahasa dan CAD, kriteria suksesnya kabur: apakah tujuannya menggantikan Rust atau Clojure, hanya menangani sebagian masalah, cukup menjadi playground pembelajaran, mengganti CAD komersial, atau juga harus berguna bagi orang lain
- Meninjau pertanyaan-pertanyaan semacam ini memang bernilai, tetapi dibanding terus meninjau banyak hal, membuat lebih banyak hal nyata tampaknya lebih baik
- Bahkan bila hasil akhirnya belakangan tampak jelas kurang baik, langsung mencobanya secara keseluruhan tetap membuat kemajuan lebih jauh
Hukum Kekekalan Perluasan Cakupan
- Waktu untuk sekadar membuat tanpa banyak berpikir juga ada batasnya dan perlu keseimbangan; pengalaman menulis banyak kode dengan agent LLM lalu akhirnya membuang semuanya kembali mengingatkan pada YAGNI
- Ada keinginan membuat pencarian fuzzy path seluruh filesystem bergaya Finda untuk dipakai di Emacs; karena fitur serupa pernah ditulis manual sebelumnya, tampaknya dengan mengawasi LLM ini bisa selesai dalam beberapa jam
- Awalnya, dalam percakapan perencanaan, Nucleo direkomendasikan; karena dirancang dan didokumentasikan dengan baik, library ini diadopsi untuk memperoleh fitur smart case dan Unicode normalization
- Sebagai contoh, query
fooakan cocok denganFoomaupunfoo, tetapiFootidak akan cocok denganfoo - Penanganan
cafedancaféberada dalam konteks yang sama
- Sebagai contoh, query
- Masalahnya bukan pada library yang bagus itu sendiri, melainkan pada fakta bahwa Nucleo juga mendukung fitur anchor
- Karena pada korpus yang hanya berisi path file anchor awal baris tampak tidak berguna, ada upaya untuk menafsirkannya sebagai anchor berdasarkan segmen path
- Contohnya,
^foodiharapkan cocok dengan/root/foobar/tetapi tidak dengan/root/barfoo/
- Contohnya,
- Untuk menanganinya secara efisien, indeks harus menyimpan batas segmen, dan query harus bisa diperiksa dengan cepat untuk tiap segmen
- Lalu query anchor dengan slash seperti
^foo/barjuga harus didukung, dan pemeriksaan per segmen saja menjadi sulit untuk mencocokkan path seperti/root/foo/bar/baz/dengan benar - Beberapa jam lagi dihabiskan untuk desain ini, bertukar ide dengan LLM, membuat kode pembungkus untuk tipe Nucleo, lalu karena kodenya terasa terlalu membesar dan tidak memuaskan, pembungkus yang lebih kecil akhirnya ditulis ulang secara langsung
- Setelah beristirahat, jadi teringat bahwa di Finda hampir tidak pernah benar-benar membutuhkan fitur anchor, dan pada korpus path, menambahkan
/di awal atau akhir query sudah bisa menggantikan sebagian besar peran anchor- Satu-satunya pengecualian yang tersisa adalah anchor untuk akhir nama file
- Pada akhirnya seluruh kode terkait anchor dibuang, dan masih sulit memastikan apakah proses itu tetap lebih menguntungkan dibanding jika dari awal ditulis sendiri tanpa diskusi dengan LLM maupun orang lain
- Makin cepat kecepatan pemrograman, tampaknya ada semacam hukum kekekalan di mana fitur yang tidak perlu, rabbit hole, dan jalan memutar ikut bertambah dalam jumlah yang sama
diff Struktural
- Dalam kode, diff biasanya berarti ringkasan perubahan per baris antara dua versi file, dan pada tampilan unified penambahan serta penghapusan ditandai dengan
+dan- - Diff yang sama juga bisa dirender dalam bentuk perbandingan kiri-kanan, dan ketika perubahan makin kompleks, bentuk seperti ini bisa lebih mudah dibaca
- Masalah pada diff per baris adalah ia tidak mengenali struktur tingkat atas seperti fungsi atau tipe; bila kurung kurawal kebetulan tetap seimbang, penandaan bahkan bisa dihilangkan walau sebenarnya bagian itu milik fungsi yang berbeda
- difftastic mencoba mengurangi masalah ini dengan memanfaatkan concrete syntax tree dari treesitter, tetapi pencocokan entitas antaversi tidak selalu berjalan baik
- Pada diff yang menjadi pemicu langsung,
struct PendingClicktidak dipasangkan sebagai entitas yang sama di kedua sisi, sehingga di kiri tampil sebagai penghapusan dan di kanan sebagai penambahan - Tanpa mendalami kenapa pencocokan itu gagal, dinilai lebih baik bila
PendingClickRequestdanPendingClicktetap terlihat saling berpadanan di kedua sisi, meski diff keseluruhannya menjadi lebih panjang
Alat diff Struktural dan Referensi
- Alat semantic diff yang dianggap paling matang dan paling hati-hati dipoles adalah semanticdiff.com
- Layanan ini disediakan oleh perusahaan kecil di Jerman, memiliki plugin VSCode gratis dan web app untuk menampilkan diff PR GitHub
- Namun tidak menyediakan library kode yang bisa dijadikan fondasi untuk workflow yang diinginkan
- Tulisan semanticdiff vs. difftastic memuat banyak detail berguna, termasuk masalah bahwa difftastic bahkan gagal menampilkan perubahan indentasi yang bermakna di Python
- Salah satu penulisnya dalam komentar HN menjelaskan bahwa mereka akhirnya meninggalkan penggunaan treesitter untuk pemrosesan semantik; parsing bisa gagal karena keyword yang bergantung konteks dan perilaku lexer, sehingga alat bahkan dapat macet ketika nama seperti
asyncdipakai sebagai parameter
- diffsitter berbasis treesitter dan menyertakan MCP server
- Jumlah GitHub star-nya banyak, tetapi dokumentasinya tidak tampak terlalu baik, dan sulit menemukan materi yang menjelaskan cara kerjanya
- Di wiki difftastic tertulis bahwa alat ini menjalankan longest-common-subsequence pada leaf tree
- gumtree adalah alat yang lahir dari latar penelitian dan akademik tahun 2014
- Karena membutuhkan Java, alat ini tidak cocok untuk kebutuhan pribadi sebagai alat yang cepat dipakai dari Emacs
- mergiraf adalah merge-driver berbasis treesitter yang ditulis dalam Rust
- Architecture overview tersusun dengan baik, dan secara internal menggunakan algoritme Gumtree
- Dari dokumentasi dan ilustrasinya, proyek ini memberi kesan ditulis dengan sangat teliti
- Penulis semanticdiff.com dalam komentar HN menulis bahwa GumTree memang cepat menghasilkan output, tetapi bahkan setelah menerapkan berbagai perbaikan dari makalah lanjutan, masih cukup sering mengembalikan pencocokan yang buruk; akhirnya mereka beralih ke pendekatan berbasis dijkstra yang meminimalkan biaya pemetaan
- weave adalah merge-driver berbasis treesitter lain yang ditulis dalam Rust
- Landing page yang mencolok, banyak GitHub star, MCP server, dan keseluruhan kesannya terlihat agak berlebihan
- Crate ekstraksi entitas sem ikut diperiksa
- Kode diff intinya cukup baik tetapi agak bertele-tele, dan pencocokan entitas memakai algoritme greedy
- Model datanya tidak dapat mendeteksi perpindahan di dalam file, padahal perpindahan semacam itu bisa bermakna besar
- Ada juga banyak analisis dampak berbasis heuristic yang tampaknya memerlukan integrasi bahasa yang lebih kuat agar bisa dipercaya
- Saat menjalankan
sem diff --verbose HEAD~4, bahkan ditemukan output bug yang menandai baris yang sebenarnya tidak berubah sebagai berubah
- Saat menjalankan
- Terlalu banyak fitur hipotetis yang terasa baru sekitar 80% selesai, sehingga kurang cocok dijadikan fondasi, meski tetap layak diapresiasi karena tingkat kemajuan ini dicapai hanya dalam 3 bulan
- diffast menghitung tree edit-distance pada AST berdasarkan algoritme dari makalah akademik 2008
- Mendukung Python, Java, Verilog, Fortran, dan C/C++ melalui parser khusus
- Example AST differences gallery tersusun dengan baik
- Informasi dapat diekspor dalam bentuk tuple untuk digunakan di datalog
- autochrome adalah alat diff khusus Clojure yang menggunakan dynamic programming
- Penjelasan visual dan walkthrough contohnya sangat bagus
- Designing a Tree Diff Algorithm Using Dynamic Programming and A* karya Tristan Hume sangat layak dijadikan referensi untuk perancangan algoritme tree diff
Workflow yang Diinginkan dan Rencana Cakupan Minimum
- Use case utamanya adalah review per giliran atas output LLM, dan agent tidak dibiarkan menghasilkan lebih dari 10 ribu baris kode sekaligus tanpa kendali
- Agent diberi tugas dengan cakupan jelas, lalu beberapa menit kemudian perubahan keseluruhan dilihat, sebelum diputuskan apakah akan diperbaiki langsung di Emacs, dibuang seluruhnya lalu dicoba lagi, atau ditulis ulang sendiri dari awal
- Workflow yang diinginkan adalah lebih dulu melihat ringkasan tingkat tinggi tentang tipe, fungsi, dan metode apa saja yang ditambah, dihapus, atau diubah
- Di atas itu, diff teks untuk tiap entitas harus bisa dibuka dengan cepat, sehingga ringkasan dapat berkembang secara alami menjadi diff detail
- Selain itu, perubahan harus bisa diedit langsung di tempat tanpa berpindah ke lokasi lain, dan diinginkan inline editing tanpa harus berpindah dari layar diff ke layar file
- Arah yang dituju adalah memindahkan workflow review perubahan dan staging Magit dari satuan file/baris ke satuan entitas
- Sesuai pelajaran tentang cakupan minimum yang kembali disadari kali ini, rencananya adalah terlebih dahulu membuat sendiri secara cepat framework ekstraksi entitas berbasis treesitter khusus untuk Rust
- Pencocokan akan dimulai dari pendekatan greedy sederhana, dan diff akan dirender ke command line
- Jika tingkat ini bisa menghasilkan hasil yang lebih baik daripada difftastic pada commit tertentu, barulah setelah itu akan dihubungkan ke workflow Emacs yang lebih interaktif seperti Magit
- Bila memungkinkan, opsi untuk memanfaatkan Magit itu sendiri juga tetap dibuka
- Dukungan bahasa baru akan ditambahkan hanya saat diperlukan
- Setelah itu, selain greedy sederhana, pencocokan global berbasis skor juga bisa dieksplorasi
- Jika hasilnya cukup memuaskan, alat itu mungkin akan dipublikasikan, tetapi mengumpulkan GitHub star atau HN karma bukanlah tujuan; bisa saja alat itu tetap menjadi alat sunyi yang dipakai sendiri
- Dengan kalimat bahwa kadang yang dibutuhkan hanyalah sebuah rak, tulisan ini kembali menegaskan sikap membuat hanya yang diperlukan, bukan melakukan ekspansi berlebihan
1 komentar
Komentar Hacker News
Menurutku ini menunjukkan dengan sangat baik kesulitan terbesar dalam riset PhD
Saat memilih topik yang menarik lalu membaca sebanyak mungkin riset terdahulu yang relevan, kita jadi sadar betapa banyak hal yang mirip dengan yang ingin kita lakukan ternyata sudah pernah dikerjakan, dan di situlah scope creep mudah menjadi parah
Setelah energi dan antusiasme awal habis, yang tersisa adalah memaksa 20–30% terakhir sampai cukup layak untuk dipublikasikan
Di hari ke-400, setelah nyaris menjelaskan teori segalanya, malah mencoba membuat perangkat eksperimen orbit titik Lagrange untuk mendeteksi partikel universal yang memediasi semua gaya di alam semesta yang diketahui
Aku penasaran bagaimana cara mengurangi hal ini
Pada praktiknya, ini sering cuma pekerjaan seperti meningkatkan observabilitas suatu sistem dari 1% menjadi 1,001%, dan lebih mirip gerbang masuk untuk karier akademik
Karena itu, aku hampir tidak pernah melihat disertasi yang benar-benar menarik, sangat baru, atau langsung bisa diterapkan pada sains
Aku hampir tidak pernah melihat orang benar-benar meneliti dengan cara itu; biasanya lebih masuk akal membaca dua atau tiga paper lalu membangun dari sana
Menyelami literatur riset secara mendalam lebih baik dilakukan setelah sudah ada hasil, saat mulai menuliskannya
Aku terus teringat ungkapan bahwa lebih baik itu sudah cukup
Perbaikan kecil akan terakumulasi seiring waktu, dan tidak ada sesuatu yang sepenuhnya baru atau sempurna sejak awal, jadi duduk diam berusaha merancang sesuatu yang sempurna justru sering menjadi bumerang
Ungkapan bahwa rintangan adalah jalan juga sangat cocok di sini
Rekan kerjaku dulu, saat mengkritik perubahan kode, kalau merasa dia sedang terlalu mempermasalahkan hal kecil, dia akan berkata, "Ini lebih baik dari sebelumnya"
Dengan begitu dia tetap menunjukkan hal yang bisa diperbaiki, sambil juga memberi izin untuk tetap lanjut meski masih ada cacat kecil, dan aku sangat mendukung sikap seperti ini
Dulu aku mengira perfeksionisme cuma berarti memaksakan diri mengejar pencapaian yang terlalu tinggi, tapi bisa juga berarti tidak mampu menerima apa pun selain yang sempurna lalu menyerah tanpa kemajuan
Prokrastinasi pada pekerjaan besar juga sering berasal dari akar yang sama
Aku suka dengan yang dikatakan CEO Rec Room
Tim hampir selalu berharap proyek dikerjakan lebih singkat; jarang sekali ada yang bilang seharusnya rilisnya lebih ditunda, dibuat lebih rumit, dan dipoles lebih jauh
Ini memang tidak 100% cocok untuk semua situasi, tetapi kalau harus membuat kesalahan, menurutku lebih baik membuat sesuatu yang kecil lalu merilisnya lebih awal daripada terlalu membesar-besarkan dan membuang waktu
Manusia pada dasarnya mudah memikirkan ide yang mirip, jadi kalau kita menyelesaikan proyek tanpa tahu apa yang sudah ada, hasilnya sering akan menjadi semacam penemuan ulang sampai taraf tertentu
Sebaliknya, kalau meneliti lebih dulu, kita bisa sadar bahwa sebagian dari itu hanya pengulangan dari sesuatu yang sudah ada dan jadi kehilangan semangat
Meski begitu, mungkin yang paling penting tetaplah membuatnya sampai selesai demi pembelajaran diri sendiri
Tentu lebih sulit jika kita harus menghasilkan kontribusi akademik baru atau mencari untung dari proyek yang benar-benar unik, tapi bahkan di ranah seperti itu pun ternyata orang sering cukup toleran selama ada sedikit sentuhan baru pada hal yang sudah ada
Aku sedang mengalami situasi seperti ini persis di side project sekarang
Bidangnya Information Retrieval, jadi pengalamanku masih sedikit dan jelas ada banyak prior art yang bisa dipelajari atau diintegrasikan
Setelah membaca tulisan ini, aku jadi lebih condong untuk membuat versiku sendiri dulu, lalu hanya melihat contoh terdahulu saat mentok atau butuh ide
Di sisi lain, dari dokumenter Clojure yang baru keluar, Rich Hickey justru tampak menghabiskan waktu lama mendalami prior art, paper, dan bahasa lain sebelum mulai bekerja
Tapi dia juga sudah pernah membuat bahasa lain sebelumnya, jadi gambaran besarnya tetap berawal dari belajar dengan cara membuat sendiri
Mungkin memang jangan terlalu lama hanya berpikir; buat saja dulu, kumpulkan pelajaran dari praktik nyata, tabrak temboknya, lalu lakukan riset yang lebih dalam saat memang mulai diperlukan
Lalu setelah menonton "Easy made Simple" dan "Hammock Driven Development", aku jadi ingin belajar Clojure
Clojure documentary on CultRepo channel: https://www.youtube.com/watch?v=Y24vK_QDLFg
Simple Made Easy: https://www.youtube.com/watch?v=SxdOUGdseq4
Hammock Driven Development: https://www.youtube.com/watch?v=f84n5oFoZBc
Menetapkan deadline menyelesaikan sebagian besar masalah scope creep bagiku
Rasanya proyek dengan tenggat keras seperti game jam atau lomba pemrograman jauh lebih mudah diselesaikan, sedangkan proyek dengan akhir yang terbuka jauh lebih sulit dituntaskan
Ini terasa mirip dengan alasan standar C++ dirilis tiap 3 tahun alih-alih menunggu sampai semua fitur yang diinginkan benar-benar siap
https://news.ycombinator.com/item?id=20428703
Tulisannya memang menarik, tetapi menurutku pikiran penulis terlihat agak tersebar dan tidak fokus
Untuk seseorang yang bilang kewalahan oleh scope creep, dia justru tampak sangat produktif, sampai di akhir tulisan ada banyak sekali tautan ke berbagai topik
Pada akhirnya dia tampak seperti tipe orang yang benar-benar suka belajar dan mencoba macam-macam, dan proses masuk ke rabbit hole itu sendiri terasa menstimulasi pikirannya dengan menyenangkan
Sebagai orang yang membangun sesuatu sendirian, ada satu kesadaran yang sangat membantuku
Kebanyakan hal yang terlihat seperti abstraksi yang wajib ternyata hanyalah scope creep dengan nama lain
Aku terus menambahkan flag untuk setiap fitur baru, lalu melihat pola di kodenya dan membuat satu aturan
Fitur tidak boleh dirilis jika tidak ada tes untuk perilaku saat flag-off
Setelah itu, aku mulai melihat flag bukan sebagai jalan keluar, melainkan sebagai bagian dari produk, dan tiga fitur yang ada di backlog menghilang begitu saja setelah kupikirkan dengan cara itu
Memang benar bahwa perencanaan berlebihan dan scope creep bisa jadi masalah, tetapi sebaliknya kita juga harus berhati-hati agar tidak terlalu bergeser ke arah pengembangan serba spontan
Beberapa proyek paling sukses yang pernah kukerjakan justru melibatkan perencanaan dan peninjauan lebih dulu terhadap sebagian besar fiturnya sambil memodelkan data, sebelum benar-benar membuat perangkat lunak yang berjalan
Pada tahap itu sering sulit tahu apa yang berlebihan, dan jika aku menghilangkan fitur yang tampaknya akan dibutuhkan olehku atau pengguna, nanti aku bisa menghabiskan banyak waktu untuk mendesain ulang inti kode secara besar-besaran
Sebaliknya, kalau tebakan awalnya meleset, proyeknya malah membesar dan kemudian kita menyebutnya scope creep
Pada akhirnya, keputusan ini bergantung pada seberapa baik kita memahami domainnya
Kalau ternyata kita kurang memahami domain dibanding perkiraan, akan banyak pengerjaan ulang; kalau ternyata kita lebih paham dari yang kita kira, mungkin sebenarnya kita bisa melangkah lebih besar tetapi malah membuang waktu dengan baby step
Ke arah mana pun, penyesalan tetap ada, jadi pada akhirnya ini terasa seperti masalah penilaian yang besar
Kita tidak boleh terjebak dalam sunk cost fallacy, dan hanya karena sudah menghabiskan beberapa jam meneliti topik setingkat PhD bukan berarti itu wajib dipakai di proyek
Kalau tidak benar-benar cocok untuk masalah saat ini, lebih baik buang saja dengan tegas