5 poin oleh GN⁺ 2025-06-18 | 1 komentar | Bagikan ke WhatsApp
  • Kompleksitas adalah elemen paling berbahaya dalam pengembangan
  • Efisiensi yang sesungguhnya lahir dari pendekatan pragmatis yang menghindari kompleksitas, seperti "solusi 80/20"
  • Penting untuk menjaga sikap yang seimbang dan fleksibel terhadap pengujian dan refactoring
  • Menekankan pemanfaatan alat serta kebiasaan menulis kode yang mudah dibaca dan mudah dikelola
  • Mewaspadai abstraksi yang berlebihan dan tren sesaat, serta merekomendasikan sikap yang mengejar kesederhanaan

Pendahuluan

  • Tulisan ini adalah kumpulan pemikiran seorang pengembang Grug Brain yang merangkum hal-hal yang dipelajari dari pengalaman selama bertahun-tahun mengembangkan perangkat lunak
  • Pengembang Grug Brain menganggap dirinya tidak terlalu pintar, tetapi telah belajar banyak lewat waktu panjang yang dihabiskan untuk pemrograman
  • Ia membagikan pemahaman yang didapat dengan cara yang mudah dan lucu, berharap orang lain bisa belajar dari kesalahan
  • Kompleksitas adalah musuh terbesar dalam hidup seorang pengembang
  • Kompleksitas menyusup diam-diam ke dalam codebase, membuat kode yang awalnya mudah dipahami perlahan menjadi nyaris mustahil diubah

Menghadapi roh jahat kompleksitas

  • Kompleksitas meresap tanpa suara seperti roh tak kasatmata, dan sering kali tidak disadari dengan baik oleh manajer proyek maupun pengembang non-Grug
  • Cara terbaik untuk mencegah kompleksitas adalah dengan mengatakan "tidak"
    • "Saya tidak akan membuat fitur ini"
    • "Saya tidak akan memperkenalkan abstraksi ini"
    • Tentu saja, dari sisi karier, berteriak "ya" mungkin lebih menguntungkan, tetapi pengembang Grug Brain lebih mementingkan pilihan yang jujur pada diri sendiri
  • Bergantung pada situasinya, kompromi ("ok") juga diperlukan, dan dalam kasus seperti ini ia lebih menyukai cara menyelesaikan masalah secara sederhana dengan solusi 80/20 (menerapkan hukum Pareto)
  • Tidak memberi tahu manajer proyek semuanya dan diam-diam menyelesaikannya dengan pendekatan 80/20 juga merupakan strategi yang cerdas

Struktur kode dan abstraksi

  • Unit kode yang tepat (cut point) akan terlihat secara alami seiring waktu, sehingga abstraksi di tahap awal sebaiknya dihindari
  • Cut point yang baik idealnya memiliki antarmuka yang sempit dengan bagian sistem lainnya
  • Upaya abstraksi terlalu dini mudah gagal, dan pengembang berpengalaman biasanya mencoba menata struktur perlahan setelah bentuk kode cukup mapan
  • Pengembang yang kurang berpengalaman atau yang "big brain" cenderung mencoba abstraksi berlebihan di awal proyek dan meninggalkan beban pemeliharaan

Strategi pengujian

  • Penting untuk menjaga keseimbangan dalam obsesi terhadap pengujian
  • Ia lebih suka menulis pengujian setelah prototyping selesai dan kode sudah agak stabil
  • Unit test dipakai di tahap awal, tetapi dalam praktiknya tahap menengah (integration test) memberi dampak paling besar
  • End-to-end test juga diperlukan, tetapi jika terlalu banyak akan menjadi mustahil dirawat, jadi pertahankan hanya sedikit jalur yang benar-benar penting
  • Saat ada laporan bug, perbaiki bug itu hanya setelah menambahkan pengujian reproduksi

Proses, Agile, dan refactoring

  • Agile tidak buruk bagi pengembang Grug, dan juga bukan yang terburuk, tetapi menaruh harapan berlebihan pada "dukun Agile" itu berbahaya
  • Prototyping, alat, dan rekan kerja yang baik sebenarnya adalah faktor keberhasilan yang lebih penting
  • Refactoring juga kebiasaan yang baik, tetapi refactoring besar dan dipaksakan itu berisiko
  • Memaksakan abstraksi yang rumit justru dapat menyebabkan proyek gagal

Pemeliharaan, perfeksionisme, dan kerendahan hati

  • Membongkar sistem yang sudah ada tanpa alasan jelas itu berbahaya, dan menghapus begitu saja "struktur yang tidak diketahui alasan keberadaannya" adalah kebiasaan yang buruk
  • Idealisme yang memimpikan kode sempurna pada kenyataannya sering menimbulkan masalah
  • Semakin banyak pengalaman, semakin terasa bahwa "kode yang bekerja harus dihormati"

Alat dan produktivitas

  • Alat pengembangan yang baik (pelengkapan kode IDE, debugger, dll.) sangat meningkatkan produktivitas, dan penting untuk memahaminya secara mendalam
  • Ditekankan bahwa nilai nyata dari type system terletak pada "auto-completion" dan pencegahan kesalahan, sementara abstraksi berlebihan dan generic justru berbahaya

Gaya kode dan pengulangan

  • Disarankan gaya seperti memecah ekspresi kondisi menjadi beberapa baris demi kode yang lebih mudah dibaca dan di-debug
  • Prinsip DRY (Don’t Repeat Yourself) tetap dihormati, tetapi yang penting adalah keseimbangan, bukan memaksakan penghapusan kode berulang
  • Dalam banyak situasi, pengulangan sederhana lebih baik daripada implementasi DRY yang rumit

Prinsip desain perangkat lunak

  • Daripada prinsip SoC (Separation of Concerns), ia lebih memilih locality of behavior, dengan argumen bahwa "kode yang menjalankan perilaku itu harus berada di objek tersebut agar lebih mudah dipelihara"
  • Callback/closure, type system, generic, abstraksi, dan sebagainya sebaiknya hanya digunakan secukupnya dan secara tepat
  • Penyalahgunaan closure dapat menciptakan "callback hell" di JavaScript

Logging, operasional

  • Logging sangat penting; log perlu ditinggalkan di setiap percabangan utama, dan di lingkungan cloud perlu disusun agar bisa dilacak dengan request ID dan semacamnya
  • Jika bisa memanfaatkan level log dinamis dan log per pengguna, itu sangat membantu pelacakan masalah saat operasional

Konkruensi, optimisasi

  • Untuk konkruensi, ia hanya mempercayai model yang sesederhana mungkin (request web tanpa state, worker queue yang dipisahkan, dll.)
  • Optimisasi sebaiknya benar-benar dilakukan hanya setelah memperoleh data profile kinerja yang nyata
  • Perlu berhati-hati terhadap biaya tersembunyi seperti network I/O, dan berbahaya jika hanya melihat kompleksitas CPU semata

Desain API

  • API yang baik harus mudah digunakan, dan desain atau abstraksi yang terlalu rumit merusak pengalaman pengembang
  • Disarankan struktur berupa "API sederhana yang cocok untuk use case utama" dan "API berlapis yang tetap memungkinkan kasus rumit diimplementasikan"

Pengembangan parser

  • Recursive descent parser memang kurang dihargai di kalangan akademis, tetapi merupakan metode yang paling cocok dan paling mudah dipahami untuk kode produksi nyata
  • Berdasarkan sebagian besar pengalaman pengembangan parser, parser yang dihasilkan oleh tool justru terlalu rumit sehingga menjadi penghambat pemecahan masalah
  • Buku yang paling direkomendasikan adalah "Crafting Interpreters", yang memuat banyak nasihat praktis

Frontend dan tren

  • Frontend modern (React, SPA, GraphQL, dll.) justru memanggil lebih banyak roh jahat kompleksitas dan sering kali tidak perlu
  • Grug sendiri lebih menyukai cara mengurangi kompleksitas dengan alat yang sederhana seperti htmx dan hyperscript
  • Di frontend memang terus muncul percobaan baru, tetapi perlu diingat bahwa banyak di antaranya hanya pengulangan ide lama

Faktor psikologis, sindrom impostor

  • Kebanyakan pengembang sering merasa "saya tidak tahu apa yang sedang saya lakukan", dan mereka perlu lebih bebas dari fenomena FOLD (Fear Of Looking Dumb)
  • Jika pengembang senior secara terbuka mengatakan "ini juga sulit buat saya, ini terlalu rumit", pengembang junior juga bisa melepaskan bebannya
  • Sindrom impostor adalah perasaan yang umum, dan pembaca didorong bahwa mereka tetap bisa tumbuh sambil terus belajar

Kesimpulan

  • Dalam pemrograman, kompleksitas harus selalu diwaspadai, dan menjaga kesederhanaan adalah inti dari pengembangan yang sukses
  • Pengalaman, pemanfaatan alat secara efektif, kerendahan hati, dan penghormatan terhadap kode yang benar-benar bekerja akan menghasilkan pengembangan yang efisien dan bernilai dalam jangka panjang
  • "Kompleksitas sangat, sangat buruk"—kalimat ini harus selalu diingat

1 komentar

 
GN⁺ 2025-06-18
Komentar Hacker News
  • Saya menganggap nilai debugger yang bagus begitu tinggi sampai rasanya tak ternilai, bahkan terasa lebih hebat dari itu. Baik di startup kecil maupun tim big tech terkenal, sering kali saya satu-satunya orang di tim yang memakai debugger. Kenyataannya, saya melihat banyak orang masih melakukan debugging dengan print. Bahkan saat saya mencoba menunjukkan workflow saya ke rekan kerja, reaksinya nyaris tidak ada. Saya setuju bahwa titik awal terbaik untuk memahami sistem adalah debugger. Berhenti di baris kode yang menarik saat pengujian lalu melihat stack jauh lebih mudah daripada mengikuti kode di kepala. Kalau sudah belajar memakai debugger, itu seperti mendapat superpower kecil yang nyata. Kalau bisa, saya benar-benar merekomendasikan untuk mencobanya
    • Saya benar-benar ingin memakai debugger sungguhan, tetapi sebagai orang yang selama ini hanya bekerja di perusahaan besar, secara realistis itu sering tidak memungkinkan. Dalam arsitektur mesh microservices, tidak ada yang bisa dijalankan secara lokal, dan bahkan di environment test pun biasanya disetel agar step debugger tidak bisa dipasang. Jadi debugging dengan print adalah satu-satunya pilihan yang memungkinkan. Bahkan kalau sistem logging juga bermasalah, atau program keburu crash sebelum sempat mengeluarkan log, maka print pun tidak bisa dipakai
    • Beberapa tahun lalu ada diskusi bagus tentang topik ini. Ada kutipan terkenal dari Brian Kernighan dan Rob Pike, dan keduanya jelas bukan developer muda. "Kami tidak menggunakan debugger untuk tujuan selain memeriksa stack trace atau beberapa nilai variabel. Struktur data dan alur kontrol yang rumit membuat orang mudah terjebak dalam detail. Jauh lebih produktif untuk memikirkan program itu sendiri lebih dalam, lalu sesekali menambahkan output print dan kode self-checking. Menambahkan print jauh lebih cepat daripada masuk langkah demi langkah dengan debugger. Selain itu, kode print tetap tinggal di program, sedangkan sesi debugging menghilang." Saya juga setuju dengan pandangan ini. Dalam sebagian besar proses development, loop print-hipotesis-jalankan memberi penyelesaian masalah yang jauh lebih cepat. Bukan berarti saya "menjalankan" kode itu di kepala, melainkan saya sudah punya model kerja atas alur kode, sehingga ketika print menunjukkan keluaran yang salah, biasanya saya bisa cepat menangkap kenyataan yang sebenarnya. Tautan terkait: The unreasonable effectiveness of print debugging
    • Alasan debugging printf selalu umum di dunia Linux adalah karena environment GUI debugger tidak bisa diandalkan. GUI Linux sering tidak stabil sehingga sulit dipercaya. Buat saya sendiri, saya mulai benar-benar memakai debugger ketika (1) GUI di Windows berjalan baik tetapi CLI sering rusak, dan (2) saya beberapa kali mengalami kode debugging print ikut masuk ke versi rilis dan menimbulkan masalah. Setelah itu saya menjalani berbagai petualangan dengan debugger CLI, dan merasa proses Junit+debugger (berbasis IDE seperti Eclipse), di mana saya bisa langsung menulis kode eksperimental lalu meninggalkannya sebagai test, senyaman Python REPL. Tentu, ada investasi awal untuk menyiapkan debugger agar cocok dengan environment
    • Pada kode saya sendiri, memakai debugger itu mudah dan saya sangat menyukainya. Tetapi begitu debugger masuk terlalu dalam ke internal library atau framework, bukan ke kode yang saya tulis, saya langsung tersesat dan tidak suka lagi. Framework/library seperti itu dibangun dengan puluhan ribu jam kerja, jadi pada level saya itu langsung melampaui batas pemahaman saya
  • Profesor Carson, kalau Anda melihat tulisan ini, saya sungguh ingin menyampaikan terima kasih. Saat kuliah dulu saya tidak mengerti kenapa kami belajar HTMX dan kenapa Anda begitu bersemangat soal itu, tetapi beberapa tahun kemudian saya benar-benar paham. HTML over the wire memang segalanya. Saat bekerja sebagai Staff Ruby on Rails Engineer, saya beberapa kali melihat pekerjaan Anda juga di Hotwire, dan kadang melihat Anda aktif di GitHub atau Hacker News pun terasa luar biasa. Anda selalu seperti cahaya bagi komunitas pemrograman. Saya menyampaikan rasa hormat dan terima kasih yang mendalam
    • Bukan cuma saya yang tersentuh di sini, ini mengharukan
    • Bukannya HTMX itu cuma meme? Karena Poe’s Law saya jadi bingung ini serius atau tidak
  • Ada banyak kutipan hebat di tulisan ini, tetapi saya paling suka bagian soal microservices: "grug tidak mengerti kenapa otak besar susah sekali memecah sistem dengan benar, lalu malah menambahkan network call ke dalamnya"
    • Sebagian orang tampaknya hanya tahu satu cara memecah sistem menjadi bagian-bagian: menjadikannya API. Kalau tidak diekspos sebagai API, mereka menganggapnya sekadar kode buram yang tidak bisa dipahami dan tidak bisa dipakai ulang
    • Agak disayangkan karena untuk berbagai alasan, microservices memang kadang praktis dan karena itu dipakai
    • Saya terus melihat bahkan untuk satu webapp kecil remeh dengan hanya lima form, tim dev kecil berisi dua orang membuatnya jadi rumit dengan struktur "microservices" (berbagi database, manajemen API, batch job lewat queue, notifikasi email, menambahkan platform observability sendiri, dan seterusnya). Lalu pada akhirnya form-form biasa pun dibuat jadi SPA karena katanya ‘lebih mudah’. Sekarang saya paham bahwa "arsitektur" dan "pattern" adalah alat pencipta kerja bagi developer yang tidak berguna. Kalau tidak ada itu, mereka mungkin akan berdiri di jalan sambil memegang papan bertuliskan "tolong beri saya sepotong sandwich saja, saya akan pakai JavaScript"
    • Teori konspirasi saya adalah pola microservices didorong oleh vendor cloud hingga hasilnya seperti ini. - Dibuat agar tak bisa dijalankan tanpa orkestrator seperti K8S, sehingga lebih mudah menjual managed cloud - Trafik jaringan/pemakaian CPU lebih tinggi sehingga tagihan ikut naik - Sulit berbagi state dalam skala besar, jadi butuh managed database/event queue - Sulit dijalankan lokal, jadi bahkan environment development pun berujung pada biaya cloud - Terkunci pada cara kerja khas cloud dan makin sulit keluar. Dulu cloud diiklankan sebagai penghemat biaya TI, lucu sekali. Sejak tahun 2000-an saya sudah tahu itu ilusi, dan hasil akhirnya selalu semua jadi lebih mahal
  • Kalimat "kompleksitas vs tatap muka melawan Tyrannosaurus, grug memilih Tyrannosaurus daripada kompleksitas: setidaknya Tyrannosaurus bisa dilihat" begitu membekas sampai saya memikirkannya setidaknya sekali seminggu
    • Kutipan: "Sambil jatuh, Leyster tetap tidak melepaskan sekopnya. Dalam kepanikan dia lupa akan fakta itu. Jadi dia mati-matian mengayunkan sekop ke kaki Tyrannosaurus muda itu..." Ini adegan yang sangat hidup menggambarkan pertarungan bertahan hidup ekstrem melawan Tyrannosaurus. Pada akhirnya, momen ketika rekannya Tamara dengan berani menusuk tepat ke tengah wajah Tyrannosaurus dengan tombak berhasil membalikkan keadaan. Pertarungan, ketegangan, dan adegan heningnya sangat berkesan
    • grug jelas belum pernah melawan Tyrannosaurus yang ‘tak terlihat’. Saya sekarang sedang duel satu lawan satu dengan Tyrannosaurus tak terlihat, dan ini benar-benar menyiksa
  • Hal yang mengagumkan dari artikel ini adalah penulisnya sebenarnya mampu melakukan hal-hal yang lebih kompleks, tetapi dari pengalaman dia memilih untuk tidak menempuh jalan itu. Tentu ada waktu dan tempat untuk abstraksi maupun kompleksitas, tetapi filosofi grug mengatakan hal-hal itu sendiri tidak punya nilai yang inheren. Menurut saya ini sangat masuk akal. Saya juga merasa AI lebih efektif pada kode yang konsisten dan berbasis data
    • Saat memakai kompleksitas dan abstraksi, itu seharusnya karena hal tersebut membuat kode lebih mudah dipahami daripada sebelumnya. Ingat premis pentingnya: ‘tidak perlu kelas tambahan khusus hanya untuk bisa memahaminya’. (Tergantung situasi)
    • "Segala sesuatu harus dibuat sesederhana mungkin, tetapi jangan terlalu sederhana"
  • Sulit dipercaya ini tulisan tahun 2022. Rasanya seperti sudah membacanya 10 tahun lalu dan menganggapnya sebagai ‘klasik’
  • Esai ini adalah tulisan favorit saya tentang membuat software. Gayanya juga menarik (meski mungkin ada orang yang merasa kurang suka), dan intinya selalu relevan
  • Potongan kode "sedih tapi nyata: belajar bilang 'ya', lalu belajar menyalahkan grug lain saat gagal, strategi karier terbaik" itu sangat realistis. Awalnya saya juga salah mengira bahwa penyebabnya di perusahaan hanyalah masalah komunikasi tim teknis, tetapi seiring waktu saya belajar bahwa memang seperti itulah kenyataannya
  • Dari semua penjelasan tentang visitor pattern yang pernah saya lihat, isi artikel ini yang terbaik
    • Saya tidak bekerja di codebase OO yang tipikal, jadi saya tidak benar-benar paham apa itu visitor pattern, tetapi saya ingin merekomendasikan buku pembuatan interpreter/VM berjudul "Crafting Interpreters". Di buku itu terlihat bagaimana visitor pattern benar-benar digunakan dalam praktik. Saya mencoba membacanya sendiri dan berusaha memahami alasan di balik kompleksitasnya, tetapi akhirnya saya menggantinya dengan tagged union. Mungkin saya memang lemah di OO, tetapi inti artikel grug juga seperti itu. Saat tidak perlu sengaja memilih kompleksitas dan indirection, ada cara yang lebih intuitif
    • Saya cukup sensitif soal penamaan, dan saya tidak suka nama visitor pattern karena terlalu samar. Saya sendiri belum pernah membuat sesuatu yang benar-benar bernama Visitor. Misalnya untuk latihan pohon sintaks (AST), penamaan konkret seperti AstWalker, AstItem::dispatch(AstWalker), AstWalker::process(AstItem) jauh lebih bermakna daripada Visitor. Kata visitor itu terlalu abstrak dan nyaris tak punya makna. Tentu hal ini tergantung konteks, dan cukup beri komentar bahwa itu adalah ‘visitor pattern’ maka tidak akan ada masalah dalam pengenalan. Dulu saya pernah harus mencocokkan dua object tree lalu membandingkan/mengimpor data, dan saya memakai nama AbstractImporter. Nama itu jauh lebih spesifik, proses dan perannya jelas. Itu berbeda dari visitor pattern yang tipikal
    • Saya mencarinya, dan ternyata memang ada penilaian "Bad". wkwk
  • Saya bagikan tulisan terkait. Ada opini lain atau tulisan tambahan dari orang lain?<br/><i>The Grug Brained Developer (2022)</i> - https://news.ycombinator.com/item?id=38076886 - Oktober 2023 (192 komentar)<br/><i>The Grug Brained Developer</i> - https://news.ycombinator.com/item?id=31840331 - Juni 2022 (374 komentar)