Waspadai Efek Makefile
(blog.yossarian.net)- Efek Makefile merujuk pada pola tidak memakai alat yang rumit atau belum familier dari awal, melainkan menyalin konfigurasi yang dulu berjalan dengan baik lalu menyesuaikannya untuk situasi baru
- Pada tahap pemecahan masalah, ini bisa menjadi respons rekayasa yang rasional karena memakai ulang contoh yang sudah terverifikasi sehingga mengurangi risiko bug
- Namun dari sudut pandang desain, ini dapat dilihat sebagai sinyal usability bahwa alat tersebut sulit atau merepotkan dipakai dari awal, sehingga perubahan terus menumpuk pada salinannya
- Alur salin-dan-ubah serupa juga muncul bukan hanya pada Make, tetapi juga di GitHub Actions, GitLab CI/CD, konfigurasi linter dan formatter, serta sistem build
- Perancang alat perlu memeriksa apakah konfigurasi dan sintaks khusus benar-benar diperlukan, apakah konvensi CLI yang sudah familier bisa dipakai ulang, dan apakah pengguna akan bergantung pada copy-paste
Apa itu Efek Makefile
- Efek Makefile adalah fenomena ketika orang tidak menulis dari awal untuk alat dengan tingkat kompleksitas atau ketidakfamilieran tertentu, tetapi menyalin dan mengubah contoh yang sebelumnya “berjalan dengan baik”
- Alur tipikalnya adalah sebagai berikut
- Ada pekerjaan berbentuk umum yang harus diselesaikan, dan pekerjaan yang sangat mirip atau identik sudah pernah dilakukan sebelumnya
- Make atau alat serupa dipilih sebagai alat yang cocok untuk pekerjaan tersebut
- Alih-alih menulis
Makefilebaru, engineer menyalinMakefiledari pekerjaan sebelumnya, lalu memperbaikinya sampai berjalan di lingkungan baru
- Make hanyalah contoh yang representatif; karena tiap tim atau individu menguasai alat yang berbeda, sebagian kelompok alat lebih rentan terhadap efek ini, sementara yang lain relatif kurang rentan
- Lelucon “heritage
Makefile” merujuk pada situasi ketikaMakefileyang diwariskan dari engineer senior, profesor, dan sebagainya terus diturunkan dengan hanya sedikit perubahan
Masalah desain alat yang terlihat dari penyalinan berulang
- Saat masalah harus segera diselesaikan, memakai ulang contoh yang berjalan bisa menjadi pilihan yang ringkas
- Karena sebagian besar pekerjaan tidak berubah, secara teori ini dapat mengurangi bug baru
- Efek Makefile pada dasarnya bukan fenomena yang buruk atau tidak efisien
- Namun pada tahap desain, ini menjadi sinyal bahwa alat atau cara penerapan alat tersebut terlalu rumit atau merepotkan
- Pengguna berulang kali menyalin solusi yang ada, bukan menyelesaikan masalah dari awal
- Jika efek ini muncul pada kasus penggunaan yang sederhana, alat tersebut mungkin terlalu kompleks untuk tujuan itu
- Pola ini juga muncul pada alat berbasis konfigurasi selain Make
- Dalam konfigurasi CI/CD, orang menyalin YAML GitHub Actions atau GitLab CI/CD dari konfigurasi terakhir yang berjalan, menjalankannya berulang kali, lalu memperbaikinya
- Konfigurasi linter dan formatter disalin antarproyek sebagai kumpulan aturan dasar, lalu diperketat atau dilonggarkan sesuai kondisi lokal
- Konfigurasi sistem build yang tidak sepele cenderung makin mirip dengan sistem build sebelumnya
Biaya pada pembelajaran, debugging, dan keamanan
- Alat dengan efek Makefile yang kuat dapat menghambat pembelajaran yang luas
- Segelintir orang mahir menyiapkan alat, sementara yang lain hanya memahami bagian yang dibutuhkan lalu menyalin dan mengubahnya
- Graf dependensi pada sistem build adalah kompleksitas yang intrinsik, tetapi keharusan mengingat perbedaan
$<dan$^di Make bukanlah demikian
- Jika dukungan diagnosis dan debugging kurang, pengguna akan bergantung pada cara menjalankan alat berkali-kali sambil hanya memperoleh petunjuk kecil
- Dalam CI/CD, debugging bergaya print harus dilakukan melalui jaringan dan lapisan orkestrasi VM perantara
- Dari sisi keamanan, risikonya juga bisa meningkat
- Langkah keamanan sering kali menuntut pemahaman mendalam tentang “mengapa” suatu perilaku terjadi
- Sistem tempat efek Makefile muncul sering kali mengizinkan kekacauan antara kode dan data, atau kekacauan sinyal in-band (in-band signaling) secara umum
- Template injection di GitHub Actions adalah contoh representatif
Pertanyaan yang perlu diperiksa perancang alat
- Saat membuat alat baru, perlu dilihat apakah pengguna bisa menulisnya dari awal, atau justru harus mencari dan menyalin “contoh yang berjalan”
- Pertanyaan untuk diperiksa adalah sebagai berikut
- Apakah kemampuan konfigurasi benar-benar diperlukan?
- Apakah sintaks khusus benar-benar diperlukan?
- Bisakah sintaks dan konvensi yang sudah familier dari alat lain atau CLI dipakai ulang?
- Apakah pembuatnya sendiri juga menyalin-tempel cara pakainya? Jika ya, pengguna lain kemungkinan juga akan begitu
- Mengenai istilah “cargo cult”, tulisan Ken Shirriff membahas masalah bahwa istilah tersebut tidak pantas sebagai jargon teknis
1 komentar
Komentar Hacker News
“Sebuah sistem kompleks yang berfungsi, tanpa kecuali, ternyata berevolusi dari sistem sederhana yang berfungsi. Sistem kompleks yang dirancang dari awal tidak akan pernah berfungsi, dan tidak bisa diperbaiki agar berfungsi. Anda harus memulai lagi dari sistem sederhana yang berfungsi”
— John Gall (1975), Systemantics: How Systems Really Work and How They Fail
https://en.wikipedia.org/wiki/John_Gall_(author)#Gall's_law
Biasanya fitur-fitur seperti tambalan mulai ditambahkan untuk menangani kasus khusus, dan itu terlihat sebagai tanda bahwa pengecualian semacam itu akan terus bertambah tanpa akhir
Ada perbedaan yang halus tetapi penting antara “menerapkan pengalaman” dan “merancang sistem yang benar-benar baru di sekitar satu hal yang secara pribadi terasa mengganggu”
Ada hipotesis lain. Sekitar 10% developer benar-benar memahami prinsipnya sehingga bisa memulai sesuatu dari nol, dan 40% lainnya bisa menangani pekerjaan sehari-hari sambil menyalin-menempel dari kode lokal, Stack Overflow, GitHub, dan LLM, dengan pemahaman kasar tentang apa yang sedang terjadi
Sisa 50% tidak banyak tahu di luar beberapa puzzle LeetCode, dan juga kurang memiliki pemahaman nyata tentang apa yang mereka salin-tempel
Jika distribusinya seperti ini, besar kemungkinan lebih dari separuh Makefile adalah potongan salin-tempel yang kurang lebih berfungsi. Kalau diambil dari tempat yang sebelumnya sudah berfungsi, pekerjaannya selesai dulu dan lanjut ke tiket berikutnya
Saya tidak menyalahkan tool itu sendiri. Makefile sudah dikenal luas dan tidak terlalu bertele-tele untuk proyek kecil. Untuk monster berisi 10.000 file, mungkin itu pilihan buruk, tetapi saya pernah melihat Makefile yang rapi bahkan di proyek raksasa. Secara pribadi itu bukan pilihan pertama saya, tetapi saya suka Makefile dan sudah memakainya sesekali selama lebih dari 30 tahun
Misalnya, saat programmer C++ mengerjakan tiket, sampai berapa lapis stack yang harus ia ketahui? Apakah harus tahu nama register CPU? Peneliti AI yang hanya memakai Jupyter harus tahu sampai sejauh apa? Mempelajari tool dan stack semaksimal mungkin memang dianjurkan, tetapi waktu terbatas
Jika terlihat aturan individual untuk membuat satu file tunggal di Makefile, saya hampir selalu menganggapnya kesalahan
Biasanya yang seharusnya ada hanyalah aturan build generik yang digunakan untuk membangun semua file dari tipe tertentu
Makefile hampir tidak perlu berisi daftar file sumber atau daftar dependensi; cukup daftar direktori tempat file sumber berada
Make harus mencari direktori sumber untuk menemukan file, mengelompokkannya berdasarkan tipe, membuat daftar dependensi, lalu memanggil aturan build yang sesuai. Setidaknya di GNU make, ini sangat sederhana dan juga dijelaskan di manual pengguna
Jika ditulis seperti ini, baik proyeknya berisi 1 file maupun 10.000 file, usaha untuk membuat atau mengubah Makefile sama-sama bisa diabaikan. Anda juga tidak perlu memperbarui Makefile setiap kali file sumber dibuat, diganti namanya, dipindahkan, atau dihapus
Alasannya, setiap bahasa dan framework punya “urutan” build yang berbeda, sehingga saya tidak bisa mengingat semuanya. Tetapi
$ makeitu mudahSaya setuju bahwa banyak developer aplikasi yang produktif mungkin tidak bisa menyiapkan proyek baru dari nol, tetapi sering kali itu lebih merupakan soal mengetahui aturan sihir dan mantra yang tepat untuk membuat berbagai tool saling cocok, bukan soal pemahaman yang mendalam
Faktor lain yang saya lihat di tempat kerja adalah alat dan sistem yang suatu saat harus ditangani developer, tetapi dalam keseharian terasa kurang bernilai untuk dipelajari
Contohnya sistem build dan konfigurasi CI. Keduanya memang diperlukan, tetapi developer tidak merasa harus menanganinya setiap hari. CI dianggap seperti sistem yang “diatur sekali lalu dilupakan”, dan muncul reaksi: apakah harus mempelajari semua ini hanya untuk membangun aplikasi?
Developer berharap semuanya “langsung bekerja”, dan kalau ada kompleksitas, mereka menganggap tim lain—orang dengan peran seperti saya—yang akan menanganinya. Karena itu, setiap kali developer menyentuh sistem ini, dorongan kuatnya adalah menyalin konfigurasi terakhir yang pernah bekerja lalu kembali ke pekerjaan yang “sebenarnya”
Solusi terbaik adalah bertemu di tengah jalan dengan developer. Sediakan alat yang sesederhana atau serumit kebutuhan tugasnya, lengkapi dokumentasi, dan minimalkan keyakinan bahwa itu “sihir”. Alat seperti Make cenderung gagal di titik ini karena terasa terlalu rumit dan seperti kotak hitam
Akibatnya siklus umpan balik menjadi sangat panjang, dan pekerjaannya sendiri terasa sangat menyakitkan
Jika developer bisa menjalankan sebagian atau seluruh pekerjaan “CI/CD” secara lokal, mereka bisa melihat, mengendalikan, dan memahaminya. Ini sangat membantu memberi rasa kepemilikan dan rasa aman, alih-alih kesan bahwa “CI/CD itu urusan dunia lain”
Ini tidak selalu berhasil. Pernah ada tim berisi dua orang yang, meski punya CI/CD wrapper tipis, tetap bersikap seolah itu proses alien dan menolak menyentuhnya
Demikian pula CI membutuhkan kepemilikan, dan cara kerja yang menjatuhkan tanggung jawab kepada developer terakhir yang mencoba memakai CI bukanlah cara kerja yang efisien
Solusinya adalah tidak mengambil alat yang dipakai perusahaan besar hanya karena perusahaan besar memakainya. Ini mungkin pendapat yang tidak populer, tetapi menurut saya CI/CD tidak diperlukan di sebagian besar tempat yang memakainya
Meski langkahnya sedikit bertambah, kita harus mencari cara membangun dan men-deploy dengan jumlah bagian bergerak yang benar-benar seminimal mungkin. Setelah itu, pertimbangkan dengan cermat biaya bagian mana yang akan diotomatisasi. Menghadirkan sistem besar untuk melakukan hal sederhana biasanya tidak bernilai dalam jangka panjang
Jika benar-benar membutuhkan CI/CD, akan ada titik sakit yang membuatnya jelas. Jika sistem itu justru menyakiti developer, berarti itu bukan alat yang tepat
maketerasa “terlalu rumit dan seperti kotak hitam”, berarti Anda belum melihatcmakeMake dan Makefile luar biasa sederhana jika tidak dibuat otomatis oleh autoconf. Jika dibuat oleh autoconf, jangan mengeditnya; itu adalah artefak build. Kalau bisa, sebaiknya autoconf juga ditinggalkan
Secara lebih luas, efek ini memang nyata. Kita bisa menjadi korbannya, atau bisa memanfaatkannya. Cara memanfaatkannya begini: tulis sedikit kode atau salin-tempel dari suatu tempat, coba di proyek, lalu rapikan sesuai kebutuhan. Saat memulai proyek berikutnya, salin kembali kode itu dan sesuaikan untuk proyek kedua. Lihat apakah perubahan tersebut bisa diterapkan kembali ke proyek asal. Jika keduanya berjalan dan tersinkron, ekstrak kode itu menjadi library. Kadang perlu lebih banyak proyek untuk memolesnya hingga berbentuk seperti library yang layak. Dalam kasus terbaik, publikasikan sebagai open source agar orang lain juga bisa memakainya
Karena Git secara internal tidak mencatat timestamp, mtime file bisa diperbarui meskipun isinya sama, dan itu memang sering terjadi, sehingga memicu rebuild yang tidak perlu
Make juga sama sekali tidak bisa menangani dengan benar alat modern yang input atau output-nya berupa seluruh direktori, atau alat yang nama output-nya belum diketahui sebelum dijalankan
Saya menyukai make, sudah menggunakannya dengan baik meski ada kekurangannya, dan tahu workaround serta workaround untuk workaround itu. Namun begitu alat mulai tidak sepenuhnya cocok dengan ekspektasi make, tingkat kesulitan dan kompleksitas untuk membuat Makefile yang benar cepat sekali melonjak
Ini bukan lelucon. Keberadaan konsep
make cleanitu sendiri adalah bukti menentukanMakefile mungkin analogi yang keliru. Masalah yang dialami kebanyakan orang dengan Makefile adalah mereka terlalu jarang menulisnya. Mereka punya gambaran umum tentang apa yang dilakukan make, tetapi tidak punya memori otot untuk menulisnya dari nol
Meski begitu, intinya benar. Saya sering melihat kode yang disalin dari web masih menyisakan banyak kode mati yang sebenarnya tidak dipakai. Kebiasaan yang baik adalah terus menghapus sampai rusak, lalu hanya mengembalikan bagian yang rusak itu. Hapus sebanyak mungkin, dan pastikan menghapus semua yang saat ini tidak digunakan
Solusi saya sejauh ini adalah membuat repositori terpisah berisi catatan tentang alat, library, dan framework semacam ini, beserta contoh program berupa shell script
Setiap kali harus memakai alat itu lagi, saya merujuk catatan untuk menyegarkan ingatan, dan jika ada hal baru yang dipelajari, catatannya diperbarui. Sekarang saya juga bisa mengarahkan LLM ke repositori itu dan bertanya
Repositori itu bersifat pribadi dan berisi informasi tentang alat yang tersedia secara publik. Pengetahuan khusus organisasi disimpan di repositori serupa tetapi terpisah, lalu dihapus ketika kontrak dengan klien atau pemberi kerja berakhir
Istilah yang paling tepat untuk ini adalah pengembangan kultus kargo. Kultus kargo muncul di Pasifik selama Perang Dunia II, ketika penduduk pulau pribumi melihat pesawat ajaib yang datang membawa makanan, minuman keras, dan perbekalan, lalu meniru tindakan para tentara, berdoa agar pesawat bambu dan perangkat dari kelapa dapat membuat para dewa terkesan sehingga perbekalan datang lagi
Masalahnya, penduduk pulau itu tidak memahami sains di balik pesawat, radio, senjata, dan semacamnya
Demikian pula, pengembang bergaya kultus kargo melihat hasil yang mungkin, tetapi tidak memahami prinsip pertama; mereka meniru tindakan para imam besar teknologi dengan harapan bisa menyalin kesuksesan
Maka jadinya terus mengulang salin, tempel, coba, utak-atik, cari, tarik, dorong, dan sesuaikan, sambil berharap kali ini setidaknya kira-kira berfungsi pada data tertentu di Selasa malam
Pada dasarnya, orang mengulang tindakan atau ritual yang sebenarnya tidak efektif dengan sendirinya, sambil mengharapkan hasil yang didapat perusahaan lain yang melakukan ritual yang sama
Yang dibicarakan artikel aslinya berbeda. Objek yang disalin, yaitu kode, memang efektif dengan sendirinya. Kita bisa mengujinya dan menilai apakah ia bekerja
Pembedaan ini penting. Karena gejala efek Makefile dalam artikel asli dan kultus kargo berbeda, menyamakan keduanya membuat diagnosis jadi sulit. Dalam kultus kargo, orang membuang waktu untuk hal-hal yang sebenarnya tidak bekerja karena takhayul. Dalam efek Makefile, sesuatu terbukti bekerja, tetapi potongan-potongan seperti organ vestigial ikut tersalin dan membuat pemeliharaan makin sulit
Secara spesifik, saya tidak menganggap ini persis sama dengan kultus kargo. Kultus kargo menyiratkan kurangnya pemahaman. Namun seseorang bisa saja memahami suatu sistem dengan baik, tetapi tetap hidup terutama dengan cara salin-tempel karena kompleksitas bawaan sistem itu mendorong salin-tempel. Itulah inti tulisannya
Biasanya saya memahami apa yang terjadi di dalamnya, tetapi beralih ke “mode” itu sendiri terasa berat secara kognitif, jadi saya menghindarinya jika bisa
Alat yang masuk kategori ini banyak berupa alat operasional yang kompleksitasnya sangat besar tetapi bukan masalah inti yang sedang saya pecahkan, seperti CI/CD, k8s, dan Docker. Make khususnya sulit untuk menghindari peralihan konteks, jadi belakangan saya cenderung menghindarinya saja
Ini tidak ada hubungannya dengan mantra ajaib, dan saya tahu kompromi yang saya ambil. Meski begitu, tetap ada risiko berubah menjadi efek Makefile
“Efek Makefile mirip dengan fenomena lain seperti kultus kargo, normalisasi penyimpangan, dan ‘bahasa write-only’. Dalam tulisan ini saya akan berargumen bahwa ini tidak secara inheren tidak efisien atau buruk, dan sedikit berbeda dari masing-masing fenomena itu karena membahas konsekuensi dari desain tertentu”
Lalu, jika seseorang benar-benar ingin “keluar dari pulau dan menerbangkan pesawat”, apakah pada akhirnya universitas adalah jalan yang paling mendekati “yang asli”?
Saya tahu sulit untuk bicara secara mutlak, ada banyak pengecualian, dan setiap orang punya berbagai pembenaran seperti “saya tidak bisa melakukan itu”. Di sini saya bertanya dari sudut pandang teori optimal. Jalur optimal untuk menghindari perilaku kultus adalah memahami keseluruhan, dan bukankah “keseluruhan” itu datang dari pendidikan tinggi?
Secara logis, sekalipun seseorang belajar sungguh-sungguh dari buku dan berusaha menyamai atau melampaui “kelengkapan” universitas, dalam beberapa hal itu tampak tetap kurang dibandingkan waktu bersama pendidik berpengetahuan di ruang kelas. Bahkan dengan asumsi orang yang sama berusaha sama kerasnya di kedua jalur
Faktor lain adalah frekuensi penggunaan. Saya menulis karya besar dengan LaTeX paling banyak sekali setahun
LaTeX pada tingkat yang saya gunakan bukanlah alat yang sulit, tetapi kalau hanya dipakai beberapa minggu dalam setahun, saya tidak mungkin mengingat detail cara pakainya, jadi biasanya saya memulai dokumen baru dengan menyalin dan menempel dari dokumen sebelumnya
Namun untuk LaTeX, meskipun dulu saya sangat sering memakainya, saya selalu menyalin dan menempel dari template. Presentasi beamer dan gambar TikZ lebih parah lagi: saya menyalin dari presentasi atau gambar sebelumnya, bukan dari template
Menurut saya TikZ memang alat yang secara inheren kompleks dan saya belum cukup mempelajarinya
Untuk LaTeX, saya merasa sudah cukup mempelajarinya, jadi mungkin ada alasan lain
Menurut saya ini bisa jadi masalah default yang wajar. Alat yang baik seharusnya menyediakan default yang baik. Namun LaTeX bukan alat yang baik menurut standar ini. Dokumen saya umumnya dimulai seperti ini Sebagian besar isinya hanya untuk mendapatkan dukungan dasar non-ASCII yang diperlukan bagi bahasa ibu saya, atau untuk mengaktifkan default yang wajar seperti kertas A4 dan microtype. Dengan alat modern seperti pandoc/Markdown, ini mungkin tidak diperlukan
Jadi tujuan menyalin dan menempel hal-hal seperti ini sering kali adalah mendapatkan default yang baik yang seharusnya sudah disediakan sejak awal oleh alat yang lebih baik
Jika tidak menulis matematika atau teks polos berbahasa Inggris saja, LaTeX rasanya seperti “baterai tidak termasuk”
Ini adalah copy-paste driven development [0], dan bukan hanya soal Makefile. Ini berkaitan dengan seluruh industri yang menyalin kode ke sana-sini tanpa tahu apa yang sebenarnya mereka salin
Sejujurnya, menurut saya Copilot membuat ini makin buruk. Karena orang menerima begitu saja bongkahan kode ke dalam codebase
[0] https://andrew.grahamyooll.com/blog/copy-pasta-driven-develo...
make, tetapi tidak pernah diberi waktu untuk menanganinya setiap hari sampai benar-benar hafalPada satu titik, saya menyerah saja. Itu berubah menjadi pengetahuan esoteris yang tidak bisa dibangun menjadi muscle memory, dan harus dipelajari ulang dari awal setiap kali dibutuhkan. Jadi saya pindah ke alat yang lebih sederhana
Hilangnya deep work bukan kesalahan programmer yang baik, melainkan kesalahan orang-orang di sisi bisnis
Saya terlalu sering melihat Makefile disalin begitu saja dari proyek lain lalu dimodifikasi agar “berfungsi”, sambil tetap menyisakan langkah build dan target yang sama sekali tidak relevan dan tidak diperlukan
Secara pribadi, ini sangat mengganggu saya
Lewat trial and error? Kalau begitu, selamat bersenang-senang :p
Memang ada banyak alat yang lebih rumit dari yang diperlukan, tetapi menurut saya Make sendiri bukan contoh yang tepat untuk itu
Pada alat modern, masalah kompleksitas sering diperparah oleh dokumentasi yang kurang, dokumentasi bergaya resep, dokumentasi yang tidak menjelaskan model konseptual yang diperlukan untuk menalar cara kerja alat, serta dokumentasi yang tidak memiliki spesifikasi yang cukup rinci dan akurat
Make tidak seperti itu. Dokumentasinya bagus, dan sebenarnya tidak sulit dipahami jika kita meluangkan waktu untuk membaca dokumentasinya
Pendekatan bergaya resep di atas mengarah pada budaya yang meremehkan pentingnya mempelajari dan memahami alat yang digunakan, serta dokumentasi menyeluruh yang memungkinkan hal itu. Atau mungkin hubungan sebab-akibatnya justru sebaliknya
Bagaimanapun, menurut saya masalahnya adalah kita terlalu sedikit meluangkan waktu untuk membuat dokumentasi alat yang komprehensif dan mutakhir, terlalu kurang merancang alat agar dokumentasi seperti itu mungkin dibuat sejak awal, dan terlalu sedikit mengalokasikan sumber daya untuk mengajarkan serta mempelajari alat yang diperlukan