Minggu Ini Ngapain

Jangan Tuker Tooling Dengan Disiplin


Sering kali ada yg nanya ke gw kenapa gw suka pake rust, kenapa gw pake typescript dengan type yg sangat strict, kenapa ci gw sangat ketat dan tooling-tooling lain yang dianggap "maso".

Salah satu alasannya ada pola yang sering gw liat kalo nemu issue. Nemu bug di prod, dicek, ketemu issuenya. Ada yang lupa ngecek satu kondisi if else. Keluarlah postmortem.

"Next time lebih teliti lagi"

Life goes on, balik kerja lagi... daaaann bulan depan kejadian lagi, beda orang, kesimpulanya? hal sama lagi... (yaa namanya juga manusia).

Dari situ gw punya prinsip

Kalau sebuah kesalahan bisa dicegah pake tooling, jangan andelin disiplin. Disiplin itu bukan solusi engineering, disiplin itu harapan.

Manusia Itu Engga Reliable, Dan Sayangnya Itu Bukan Masalah Moral

Manusia capek. Manusia ngejar deadline. Manusia ngoding jam 2 pagi sambil setengah mikirin hal lain (surely bukan gw :clueless:).

Lengah itu bukan karena bodoh atau males, itu sifat bawaan manusia. Jadi kalau sistem lu butuh manusia yang engga pernah lengah biar aman, yang salah desain sistemnya, bukan manusianya.

Toyota udah paham ini dari jaman dulu. Ada konsep namanya poka-yoke (mistake proofing), design proses nya biar kesalahan itu engga mungkin, bukan nyuruh orang lebih hati-hati. Contoh gampangnya colokan yang bentuknya cuma bisa masuk satu arah. Engga perlu tutorial "cara nyolok yang benar", bentuknya aja yang engga bisa bikin salah.

Di software, ide ini pernah ditulis di essay Discipline doesn't scale. Intinya, kalau lu minta satu tim buat lebih disiplin, cuma sebagian yang ngikutin. Dan yang ngikutin pun bakal lengah di hari yang salah.

grafik disiplin vs tooling seiring skala
Makin gede tim & kode, efektivitas disiplin turun. Tooling cenderung flat.

Pake Formatter Ga Perlu Mikir

Contoh paling keliatan itu formatting. Dulu tab vs space, kutip satu vs kutip dua, posisi kurung kurawal, itu semua materi debat code review.

Solusi nya waktu itu style guide. Docs verbose yang semua orang harus inget dan reviewer harus jagain.

Terus muncul gofmt, clang-format, prettier, dan kawan 1kawan. Aturan yang tadinya dijaga manusia, dipindahin ke tools yang selalu bisa ngecek.

# .github/workflows/ci.yml. CI yang ngecek kode engga keformat
- run: prettier --check .
- run: cargo fmt --check

Tinggal setup formatter jalan otomatis pas save, CI nolak yang engga rapih. Engga perlu inget lagi aturannya, engga ada lagi yang bisa lengah karena lupa sedikit. Sampe sampe ada quote terkenal dari Rob Pike

Gofmt's style is no one's favorite, yet gofmt is everyone's favorite.

(katanya sih gitu tapi gw sih pake gofumpt karena memang ga suka gofmt 😔)

Memory Management, Katanya Skill Issue Kalo Ada Bug

Contoh lain, manual memory management di C

char *data = malloc(100);
process(data);
free(data);
// ... 200 baris kemudian, ditulis 2 tahun kemudian, sama orang beda... atau sama claude
log_debug(data); // use after free

Aturannya terlihat jelas. Yang malloc harus free, yang udah difree jangan disentuh. Not that complex.

Sekarang liat siapa yang gagal ngejaga aturan simpel ini :D. Programmer kernel Linux, programmer Chrome, programmer Windows.

statistik memory safety bug microsoft dan android
Kalau programmer sekelas mereka aja gagal, kita gimana?

Ini bukan programmer yang punya "skill issue", orang jago ini. Kalau mereka aja bisa gagal, ya gimana kita 😭. Kebelutan tooling yang buat ngurus ini bisa dateng bertahap.

  1. Deteksi pake valgrind & AddressSanitizer (ASan). Use after free ketangkep pas test, bukan pas production.
  2. Pencegahan pake Rust, borrow checker itu literally aturan disiplin memory management yang dipaksa ke compiler.

Hasilnya keliatan di data (grafik di atas, maaf bagus). Setelah kode android banyak ditulis di rust, memory safety bug turun dari 76% ke bawah 20% (Rust BTW).

Disiplin puluhan tahun kalah sama compiler yang galak. Dan borrow checker emang cukup nyebelin. Tapi yaaa ada buktinya kalau ada benefitnya

Dynamic vs Static Typing

Nah ini yang sering jadi perdebatan orang orang. Menurut gw ini debat disiplin vs tooling juga.

Dynamic typing itu pada dasarnya kontrak yang dijaga disiplin.

function hitungTotal(items, discount) {
  // items itu apa? array? array of apa?
  // discount itu 0.1 atau 10? number kan ya? kan? KAN?
}

Siapa yang jagain items beneran array dan discount beneran number? sayangnya programmer (kita).

Alatnya manual semua, naming convention, jsdooc yang harus diupdate manual, test yang ngecek return function, atau paling sering, inget inget aja (i am the documentation). Kayak di ruby itu kalo value return bool dia pake ? di akhir variable. Kayak has_key?. Itu padahal bisa diganti dengan static typing. Static typing itu mindahin kontrak ke compiler.

function hitungTotal(items: Item[], discount: number): number

Sekarang "kontraknya" dicek di setiap funtion call, setiap refactor, setiap pr. Compiler untungnya engga capek (kalo iya gw udh disembur rustc), engga lupa, dan engga lagi buru-buru LGTM pr dulu sebelum release cycle yang janjinya bakal fix techdept next cycle hahaha... haha.. (help)

Dan ini bukan cuma feeling gw. Ada studynya yg bahas ini, To Type or Not to Type (ICSE 2017):

15% bug public di project JavaScript kedeteksi cuma dengan nambahin type annotation, tanpa nulis satu test pun.

Ini bug yang udah lolos code review dan testing sampe jadi bug report public. Yang menurut gw paling menarik itu arah perkembangan programming language sekarang:

  • Python nambahin type hints + mypy
  • JavaScript → TypeScript, default hampir semua project baru
  • PHP nambahin type declaration
  • Ruby bikin RBS + Sorbet
  • Elixir nambah gradual static type check

Semua bahasa dynamic yg cukup gede lagi berusaha nambahin static typing. Ini industri secara kolektif ngaku kalo kontrak yang dijaga disiplin doang itu engga jalan di scale dan perlu tooling yang lebih baik.

📒 Bukan berarti dynamic typing useless ya. Buat prototype dan quick script, cost nulis tipe kadang engga sebanding (gw juga masih suka nulis script python tanpa type hint). Dan static typing bukan jaminan bebas bug, dia cuma ngecilin ruang state yang mungkin.

Terus Disiplin Buat Apa?

Bukan berarti disiplin engga penting. Ada banyak hal yang tooling belum bisa jagain. naming yang masuk akal, arsitektur yg masuk akal, test yang berguna, design yang oke.

Justru karena itu disiplin harus dihemat. Disiplin itu resource terbatas, ya setidaknya otak itu ada batasannya belom bisa 100% jalan terus. Tiap aturan yang harus diinget itu jadi makan jatah fokus.

Kalau reviewer masih mikirin spasi dan tipe parameter, kapan mikirin logic nya sigh?

Biarinlah formatter ngurusin spasi, compiler ngurusin tipe, rust replace c, biar manusia fokus ke hal yang emang butuh campur tangan manusia. Rule of thumb gw jadinya

  • Kalau aturan bisa dienforce compiler/linter/CI, enforce. Aturan yang cuma ada di docs itu saran, bukan aturan.
  • Kalau kesimpulan postmortem nya "harus lebih hati-hati", itu belum selesai. Cari tooling yang bikin kesalahan itu engga bisa keulang.
  • Disiplin idealnya dipake buat hal yang emang belum ada tooling nya.

Jadi kalau ada yang bilang "engga perlu typescript/linter/rust, cukup hati-hati aja. lu itu skill issue", perlu inget, semua orang yang pernah bikin bug juga niatnya engga mau bikin bug. Manusia bakal tetep lengah, itu engga bisa dinego. Yang bisa dipilih cuma satu

Lengahnya ketangkep compile error, atau lengahnya jadi insiden production jam 2 pagi masuk pageduty

Comments

Comments section - you can integrate Giscus or another commenting system here.