- Karena kode menimbulkan biaya pemeliharaan sejak saat ditulis, struktur yang mudah dihapus atau diganti di kemudian hari sering kali lebih penting daripada reusability
- Semakin banyak pengguna API, semakin besar biaya perubahan; semakin dalam ketergantungan pada API pihak ketiga, semakin besar codebase terguncang oleh perubahan eksternal
- Duplikasi, boilerplate, layering, bongkahan kode besar, pemisahan modul, dan feature flag semuanya bisa menjadi alat manajemen dependensi, tergantung situasinya
- Pemisahan yang baik bukan sekadar mengelompokkan fungsi umum, melainkan lebih mirip menyembunyikan keputusan desain yang sulit diubah atau berpeluang besar berubah dari satu sama lain
- Kode yang baik bukan kode yang sempurna sejak awal, melainkan kode legacy yang semakin lama semakin tidak mengganggu; pada akhirnya, itu adalah kode yang mudah dihapus
Kode adalah biaya, dan penghapusan adalah penghematan biaya
- Semua kode menciptakan biaya pemeliharaan sejak saat ditulis; reuse dapat mengurangi jumlah kode, tetapi bisa membuat kita lebih sulit mengubah pikiran nanti
- Semakin banyak kode yang menggunakan sebuah API, semakin besar biaya penulisan ulang saat API itu berubah
- Semakin banyak kita bergantung pada API pihak ketiga, semakin besar pula dampak yang diterima saat API tersebut berubah
- Dalam sistem berskala besar, seiring waktu semakin sulit memahami bagaimana kode saling terkait dan bagian mana bergantung pada bagian mana
- Jika jumlah baris kode dilihat bukan sebagai “baris yang diproduksi” melainkan sebagai “biaya yang dikeluarkan”, menghapus kode berarti menurunkan biaya pemeliharaan
- Tujuannya bukan hanya membuat perangkat lunak yang bisa digunakan ulang, tetapi membuat perangkat lunak yang bisa dibuang
Tahap 0: Jangan menulis kode
- Jumlah baris kode memang tidak menjelaskan segalanya, tetapi skala seperti 50, 500, 5.000, 10.000, atau 25.000 baris tetap penting
- Monolith 1 juta baris membutuhkan lebih banyak waktu, biaya, dan usaha untuk diganti dibanding monolith 10 ribu baris
- Semakin banyak kode, semakin sulit dihilangkan; tetapi mengurangi satu baris kode saja hampir tidak menghemat apa pun
- Kode yang paling mudah dihapus adalah kode yang tidak pernah ditulis sejak awal
Tahap 1: Lakukan copy-paste
- Kode yang reusable lebih mudah dibuat setelah beberapa use case benar-benar muncul, bukan dengan menebak penggunaan masa depan sejak awal
- Mencoba copy-paste beberapa kali di codebase membantu memahami cara penggunaan yang sebenarnya
- Begitu suatu kode dijadikan API bersama, kode itu menjadi sulit diubah
- Kode yang memanggil fungsi tidak hanya bergantung pada perilaku yang terdokumentasi, tetapi juga pada perilaku sengaja maupun tidak sengaja yang teramati dari implementasinya
- Menghapus kode di dalam sebuah fungsi lebih sederhana daripada menghapus fungsi itu sendiri
Tahap 2: Berhenti copy-paste
- Kode yang sudah cukup sering berulang sudah saatnya dinaikkan menjadi fungsi
- Ini mencakup kode utility yang sering dibutuhkan di atas standard library, seperti kode yang membuka file konfigurasi lalu mengembalikan hash table, atau kode untuk menghapus direktori
utillebih baik dibuat sebagai direktori daripada satu file, dengan utility berbeda ditempatkan di file berbeda- Satu file
utilakan terus membesar, dan setelah terlalu besar akan sulit dipecah
- Satu file
- Kode yang kurang spesifik terhadap aplikasi atau proyek lebih mudah digunakan ulang dan lebih kecil kemungkinan berubah atau dihapus
- Ini mencakup kode library seperti logging, API pihak ketiga, file handle, dan process
- List, hash table, dan collection jarang dihapus bukan hanya karena interface-nya sederhana, tetapi juga karena cakupannya tidak membesar seiring waktu
- Intinya adalah menempatkan bagian yang sulit dihapus sejauh mungkin dari bagian yang mudah dihapus
Tahap 3: Tulis lebih banyak boilerplate
- Membuat library dapat menghindari copy-paste, tetapi dalam praktiknya kita sering menulis banyak boilerplate untuk menggunakan library tersebut
- Boilerplate mirip copy-paste karena setiap kali kita mengubah bagian yang sedikit berbeda di tempat berbeda
- Duplikasi seperti ini adalah cara menerima verbositas sebagai harga untuk mengurangi dependensi dan mendapatkan fleksibilitas
- Library yang membutuhkan boilerplate sering muncul saat sulit mencampur policy dan protocol, seperti network protocol, wire format, dan parsing tool
- Protocol menangani apa yang bisa dilakukan program
- Policy menangani apa yang harus dilakukan program
- Kode seperti ini sering merupakan kebutuhan untuk berkomunikasi dengan komputer lain atau menangani file lain, sehingga sulit dihapus
- Penting untuk tidak menyebarkan business logic ke dalam kode seperti ini
- Walaupun harus menulis lebih banyak baris, lebih baik menulis baris itu di bagian yang mudah dihapus
Tahap 4: Jangan menulis boilerplate
- Jika boilerplate sudah terlalu banyak, sudah saatnya membuat library yang membungkus library fleksibel dengan opini tentang policy, workflow, dan state
- Membuat API yang mudah digunakan mirip dengan melibrary-kan boilerplate
- Python HTTP client
requestsadalah contoh yang menyediakan interface sederhana di atasurllib3yang lebih verboserequestsmenangani workflow umum penggunaan HTTP dan menyembunyikan detail praktisurllib3menyediakan pipelining, connection management, dan lainnya tanpa menyembunyikan detail dari pengguna
- Membungkus satu library dengan library lain bukan hanya soal menyembunyikan detail, tetapi juga separation of concerns
- Sebaiknya jangan menaruh business logic di direktori
util; lebih baik menumpuk library yang mudah digunakan di atas library yang sederhana untuk diimplementasikan - Kadang library pihak ketiga juga sebaiknya dibungkus
- Agar seluruh proyek tidak terkunci pada pilihan tertentu, kita bisa membuat library yang sesuai dengan kode kita sendiri
- API yang nyaman digunakan dan API yang mudah diperluas sering kali saling bertentangan
- Layering lebih dekat pada membuat kode yang sulit dihapus menjadi nyaman digunakan tanpa mencemari business logic, daripada menulis kode yang akan dihapus nanti
Tahap 5: Tulis bongkahan kode besar
- Walaupun kita melakukan copy-paste, refactoring, layering, dan composition, pada akhirnya kode harus melakukan sesuatu; kadang kita membutuhkan bongkahan kode besar yang menahan bagian lainnya tetap bersama
- Business logic dapat ditandai oleh edge case tanpa akhir dan hack cepat
- Kode game atau kode founder juga bisa dilihat sebagai jenis kode yang sama, yang mengambil jalan pintas demi menghemat banyak waktu
- Kadang lebih mudah menghapus satu kesalahan besar daripada menghilangkan 18 kesalahan kecil yang saling terkait
- Banyak pemrograman bersifat eksploratif, sehingga beberapa kali salah dan beriterasi bisa lebih cepat daripada mencoba benar sejak awal
- Saat membuat game pertama, jangan mulai dengan membuat engine; sebelum menulis aplikasi, sebaiknya jangan mulai dengan membuat web framework
- Monorepo juga merupakan trade-off serupa
- Sulit mengetahui sejak awal bagaimana kode harus dipisah, dan satu kesalahan besar lebih mudah di-deploy daripada 20 kesalahan yang terikat kuat
- Jika kita tahu kode itu akan segera dibuang, dihapus, atau mudah diganti, kita bisa mengambil lebih banyak jalan pintas
- Tujuannya bukan mengulang bongkahan lumpur yang sama sepuluh kali hingga menyempurnakan kesalahan, melainkan membuat kesalahan baru setiap kali, mengambil risiko baru, dan membangun lewat iterasi
- Proyek pada akhirnya akan gagal atau menjadi kode legacy, dan kegagalan terjadi lebih sering daripada keberhasilan
- Menghapus semuanya sekaligus lebih mudah daripada menghapus kode sepotong demi sepotong
Tahap 6: Pecah kode menjadi bagian-bagian
- Big ball of mud adalah yang paling mudah dibuat, tetapi biaya pemeliharaannya paling besar
- Perubahan yang tampak sederhana bisa membuat hampir seluruh codebase harus disentuh secara tambal sulam
- Kode yang mudah dihapus secara keseluruhan menjadi sulit dihapus per bagian
- Modul sebaiknya dipisah bukan berdasarkan fungsi umum, melainkan berdasarkan hal yang tidak dibagi dengan bagian lain dan keputusan desain yang harus disembunyikan
- Seperti kriteria D. Parnas, kita bisa membuat daftar keputusan desain yang sulit atau berpeluang besar berubah, lalu merancang setiap modul agar menyembunyikan keputusan tersebut dari modul lain
- Modul dibuat bukan demi reuse, melainkan demi kemungkinan perubahan
- Single responsibility principle dapat dilihat sebagai “setiap modul harus menangani hanya satu masalah sulit”, tetapi yang lebih penting adalah “setiap masalah sulit harus ditangani hanya di satu modul”
- Jika sebuah modul melakukan dua hal, sering kali itu karena untuk mengubah satu bagian kita juga harus mengubah bagian lainnya
- Satu komponen buruk dengan interface sederhana bisa lebih mudah daripada dua komponen yang membutuhkan koordinasi cermat
Loose coupling dan interface umum
- Sistem yang dapat menghapus sebagian tanpa menulis ulang bagian lain biasanya disebut loose coupling
- Loose coupling dekat dengan keadaan di mana kita tidak perlu mengubah terlalu banyak kode saat berubah pikiran
- Meng-hardcode variabel sekali, atau bahkan menggunakan command-line flag alih-alih variabel, dalam kondisi tertentu bisa menjadi loose coupling
- Microsoft Windows mencapai tujuan ini dengan memisahkan API eksternal dan API internal
- API eksternal terikat pada lifecycle program desktop
- API internal terikat pada kernel dasar
- Dengan menyembunyikan API, fleksibilitas bisa diperoleh tanpa merusak banyak software
- HTTP juga memberi contoh loose coupling
- Cache bisa ditempatkan di depan HTTP server
- Gambar dapat dipindahkan ke CDN dan cukup mengubah link tanpa merusak browser
- HTTP error code memberi kode unik untuk masalah umum sehingga client dapat menangani banyak error sebagai gantinya
- Cara menangani kegagalan harus dipertimbangkan bersama saat memecah kode menjadi bagian-bagian kecil
Penanganan kegagalan dan tingkat coupling
- Erlang/OTP menggunakan cara yang relatif unik untuk menangani kegagalan melalui supervision tree
- Setiap process dalam sistem Erlang kurang lebih dimulai dan diawasi oleh supervisor
- Jika process bermasalah, process tersebut dihentikan
- Jika process berhenti, supervisor memulainya kembali
- Supervisor dimulai oleh bootstrap process, dan jika supervisor gagal, bootstrap process memulainya kembali
- Ide intinya adalah lebih cepat gagal dan restart daripada menangani error
- Kegagalan sementara kadang dapat ditekan dengan cara mematikan lalu menyalakan kembali
- Error handling dan recovery sebaiknya dilakukan di layer luar codebase; ini dikenal sebagai end-to-end principle
- Lebih mudah menangani kegagalan di kedua ujung koneksi daripada di tengah, dan sekalipun ditangani di dalam, pemeriksaan tingkat atas tetap diperlukan
- Error handling adalah salah satu dari banyak cara yang dapat mengikat sistem dengan kuat
IMAP, file system, SQL, middleware
- IMAP menyakitkan dalam hal error handling karena hampir setiap operasi berbentuk pengecualian dengan opsi dan penanganan tersendiri
- Dalam IMAP, error dapat muncul di tengah hasil operasi lain
- Alih-alih UUID, dibuat token unik untuk mengidentifikasi setiap pesan, dan token ini pun dapat berubah di tengah hasil operasi
- Banyak operasi IMAP tidak atomic
- Butuh lebih dari 25 tahun hingga muncul cara untuk memindahkan email dari satu folder ke folder lain secara andal
- Ada juga encoding UTF-7 khusus dan encoding base64 yang unik
- File system dan database menjadi pembanding yang lebih baik untuk remote storage
- File system memiliki kumpulan operasi tetap dan banyak objek
- SQL terlihat seperti interface yang lebih luas daripada file system, tetapi mengikuti pola banyak operasi atas set dan banyak row
- Database tidak selalu bisa saling dipertukarkan, tetapi lebih mudah menemukan sesuatu yang bekerja dengan SQL daripada query language buatan sendiri
- Finagle dari Twitter menggunakan API umum untuk service sehingga timeout handling, retry mechanism, dan authentication check dapat mudah ditambahkan ke kode client maupun server
- Contoh bagus loose coupling sering kali juga merupakan contoh uniform interface
- Codebase yang sehat tidak harus termodularisasi sempurna, tetapi harus memiliki jarak yang cukup di antara bagian-bagian yang bergerak
- Kode yang loosely coupled tidak selalu mudah dihapus, tetapi jauh lebih mudah diganti dan diubah
Tahap 7: Terus menulis kode
- Jika kita bisa menulis kode baru tanpa berurusan dengan kode lama, jauh lebih mudah bereksperimen dengan ide baru
- Intinya bukan microservices atau monolith, melainkan selama kita mencari tahu apa yang dilakukan sistem, kita harus bisa menaruh satu atau dua eksperimen di atasnya
- Feature flag adalah cara untuk memungkinkan kita berubah pikiran nanti
- Feature flag tidak hanya untuk eksperimen fitur, tetapi juga memungkinkan perubahan di-deploy tanpa redeploy software
- Google Chrome menemukan bahwa bagian tersulit dalam siklus rilis reguler adalah waktu yang dibutuhkan untuk menggabungkan feature branch yang sudah berjalan lama
- Jika kode baru bisa dinyalakan dan dimatikan tanpa recompilation, perubahan besar dapat dipecah menjadi merge kecil dan tidak perlu memengaruhi kode yang sudah ada
- Jika fitur baru muncul lebih awal di codebase yang sama, dampak pengembangan fitur jangka panjang terhadap bagian lain menjadi lebih jelas
- Feature flag bukan sekadar command-line switch, melainkan cara memisahkan rilis fitur dari branch merge dan deployment kode
- Saat deployment software baru bisa memakan waktu berjam-jam, berhari-hari, atau berminggu-minggu, kemampuan untuk berubah pikiran saat runtime menjadi semakin penting
Kode yang baik adalah kode legacy yang tidak mengganggu
- Yang lebih penting daripada fakta bahwa kita beriterasi adalah memiliki feedback loop
- Intinya adalah mengisolasi komponen untuk perubahan, bukan membuat modul demi reuse
- Menanggapi perubahan mencakup bukan hanya pengembangan fitur baru, tetapi juga penghapusan fitur lama
- Menulis kode yang extensible berarti berharap pilihan awal tetap benar tiga bulan kemudian
- Kode yang deletable berangkat dari asumsi sebaliknya
- Layering, isolasi, interface umum, dan composition adalah cara membuat software yang bisa berubah seiring waktu, bukan sekadar software yang baik itu sendiri
- Tidak semuanya perlu dibuang, tetapi sebagian harus dihapus
- Kode yang baik bukan kode yang benar sejak awal, melainkan kode legacy yang tidak mengganggu
- Kode yang baik adalah kode yang mudah dihapus
1 komentar
Pendapat di Hacker News
Ungkapan yang saya suka adalah kesederhanaan itu ketangguhan
Mirip dengan hukum perubahan berkelanjutan Lehman, artinya semakin rendah kompleksitas sistem, semakin mudah sistem itu diubah
Menurut saya, daripada menulis kode yang dapat diperluas untuk berjaga-jaga terhadap masa depan, lebih baik mempersiapkan masa depan dengan kode yang intuitif
Misalnya, lakukan abstraksi hanya ketika benar-benar diperlukan, izinkan duplikasi sederhana, mulai dengan monolit di awal, dan dahulukan scaling vertikal sebelum scaling horizontal
Saya pernah membuat beberapa sistem 0→1, dan pola yang sama semuanya mengarah ke sini
https://en.m.wikipedia.org/wiki/Lehman%27s_laws_of_software_...
Kode tidak menjadi tangguh hanya karena tidak menangani kasus tepi, meskipun terlihat lebih sederhana
Perdebatan terbuka tentang apa itu “kesederhanaan” dan bagaimana menerapkannya pada sistem, dan ini juga pertanyaan yang cukup rumit sampai-sampai dibahas oleh Rich Hickey
Mungkin “yang bodoh itu tangguh” atau “yang lugas itu tangguh” bisa lebih tepat menangkap maksudnya
Cukup tulis kode yang melakukan apa yang diperlukan. Jangan membuat masalah skalabilitas khayalan, jangan membuat abstraksi cerdik agar terlihat pintar, tulis sebagai monolit lalu taruh di VM dan bisa langsung masuk produksi
Kalau ada masalah, selesaikan saat itu, dan sebaiknya setelah arus kas sudah positif
Mengapa startup “AirBnb untuk anjing” dengan 0 pengguna mengkhawatirkan C100K? Apakah AWS membujuk Anda membayar serverless demi keuntungan Anda, atau demi mengeruk uang?
Artikel terkait:
Write code that is easy to delete, not easy to extend (2016) - https://news.ycombinator.com/item?id=24989351 - Nov 2020 (30 comments)
Write code that is easy to delete, not easy to extend (2016) - https://news.ycombinator.com/item?id=23914486 - July 2020 (109 comments)
Write code that is easy to delete, not easy to extend - https://news.ycombinator.com/item?id=18761739 - Dec 2018 (2 comments)
Write code that is easy to delete, not easy to extend - https://news.ycombinator.com/item?id=11093733 - Feb 2016 (133 comments)
Jika merangkum singkat kesalahan yang saya buat saat masih muda, sekarang saya justru percaya pada desain untuk dihapus
Dulu saya berpikir bisa membuat karya seni yang hebat, yang mengantisipasi semua situasi dan memenuhi semua kebutuhan. Namun tidak ada orang yang bisa memprediksi kebutuhan masa depan sebaik itu
Suatu hari nanti, apa yang saya buat akan menjadi “benda bodoh itu” bagi seseorang, dan betapapun bangganya saya sekarang, bisa jadi sah-sah saja bagi mereka untuk menghancurkannya sepenuhnya
Jadi lebih baik mencurahkan tenaga untuk membuatnya mudah dihilangkan. Ini sering mengurangi coupling, tetapi yang penting adalah bahwa ini berbeda dari decoupling ala developer muda penuh semangat yang ingin memisahkan semuanya menjadi framework yang bisa dikonfigurasi secara meta
Terkadang coupling yang kuat tetapi mudah dipahami justru lebih baik
https://news.ycombinator.com/item?id=41219130
Misalnya muncul hal-hal seperti CommonExcelFileParser, CommonExcelFileParserUtilities, HasExcelParseStatus, ProductImportExcelParser, ProductImportExcelParserView, ProductImportExcelParserResultHandler, lalu semuanya menjadi fondasi bagi kode di sekitarnya
Ini mirip dengan memulai proyek frontend dengan React atau Angular, lalu berpindah ke yang lain menjadi tugas Sisifus
Dalam praktiknya, orang-orang akhirnya membuat seluruh platform, dan meskipun ada pilihan yang akan menimbulkan masalah di masa depan, karena coupling, refactoring menjadi jauh lebih sulit dibanding codebase yang kurang diabstraksikan
Orang-orang tampaknya lebih menyukai hal seperti ini daripada menerapkan KISS dan YAGNI serta membuat kode yang mudah dihapus, jadi saya tidak tahu harus bagaimana ketika itu terjadi
Kebutuhan bisnis berubah dan bergerak, jadi jangan mencoba memprediksinya; tulislah sesuatu yang mudah diganti atau dibuang
Framework dan library agak berbeda. Keduanya memang harus mengikuti perubahan dunia, tetapi bisa melakukannya dengan laju yang jauh lebih moderat
Masalah terbesar adalah ketika dalam aplikasi bisnis yang sudah memakai framework seperti Rails atau Asp.Net, para developer masih ingin membuat “framework” lagi
Jika Anda tidak sedang menulis kernel Linux, jangan menulis seperti kernel Linux
Cukup aneh bahwa tulisan ini sama sekali tidak membahas pengujian dan observabilitas
Pengujian juga punya biaya pemeliharaan, tetapi mengurangi risiko merusak sesuatu saat kita menghapus sesuatu
Selain itu, jika layanan sudah diekspos ke pemanggil eksternal, kita membutuhkan baik cara yang kokoh untuk menandai sebagian pemanggilan sebagai akan dihentikan lalu menghapusnya nanti, maupun cara mengamati apakah pemanggilan itu masih terjadi dan siapa yang memanggilnya
Baru-baru ini untuk pertama kalinya kami menghapus resolver GraphQL yang terekspos secara semi-otomatis, dan karena kami sudah punya metrik tentang seberapa sering resolver tertentu dipakai, kami mem-parsingnya untuk mendapatkan daftar resolver yang tidak bisa dihapus
GraphQL memang sudah punya anotasi deprecated, tetapi layanan kami tidak menangani anotasi itu secara khusus
Jadi kami menambahkan observabilitas yang menandai ketika fungsi deprecated dipanggil, menjalankannya cukup lama di production, lalu bisa menghapus kode yang terekspos ke luar dengan aman
Begitu kita mulai membuatnya terlalu rumit, semuanya menjadi kekacauan yang saling terhubung, dan developer tidak lagi tahu dampak sebuah perubahan
Tentu ada banyak cara untuk mengacaukannya. Kita bisa mengikuti prinsip “best practice” yang bodoh, atau melakukan “microservices” dengan cara yang membuat kita tidak tahu siapa yang mengonsumsi layanan apa. Tetapi kalau begitu, kita tidak membuatnya mudah dihapus
Konsumsi eksternal adalah contoh yang bagus. Memberi konsumen peringatan yang wajar tentang penghentian layanan itu masuk akal, tetapi jika kita tidak bisa benar-benar mematikannya saat ingin, itu bukan sistem yang dirancang agar mudah dihapus
Jika pendekatan itu tepat, silakan saja. Namun berharap pengujian dan observabilitas memberi tahu apakah sesuatu rusak kemungkinan besar tidak akan bekerja dengan baik
Saya tidak menentang pengujian itu sendiri, tetapi sebagai pagar pengaman yang memberi tahu apakah kita merusak sesuatu dalam rantai yang panjang dan rumit, sulit menyebutnya sangat bagus. Karena sangat sulit juga memiliki cakupan pengujian yang benar-benar akan melindungi kita
Jika sebagian kode dihapus, sebagian pengujian juga bisa dihapus
Seperti dalam tulisan itu, bisa dianggap bahwa tulisan hanya membahas kode dan dampak terkait pada pengujian sudah tersirat
Hanya karena tulisan itu tidak menyebut pengujian, kita tidak bisa berasumsi bahwa maksudnya jangan menulis pengujian
Melihat bagian ini, saya merasa judulnya tidak selalu benar: kode yang mudah dihapus sering kali juga merupakan kode yang mudah diperluas
Karena kode itu berlapis, modular, dan mengisolasi bagian-bagian berbeda melalui abstraksi seperti interface atau kontrak tipe lain
Saya biasa mengatakan kepada mahasiswa fisika komputasi bahwa komputasi terbaik adalah komputasi yang tidak perlu dilakukan
Secara pribadi, saya membagi kode menjadi dua bagian: logika bisnis dan implementasi nyata
Logika bisnis pada dasarnya bisa saja berulang, tetapi detail teknis tidak boleh terlalu banyak berulang
Implementasi nyata boleh sekotor apa pun selama tidak memuat logika bisnis secara langsung dan tetap independen dari aplikasi
Dengan begitu, ketika kita sadar ada sesuatu yang berantakan dan tidak berjalan baik, kita punya opsi untuk menghapus seluruh implementasi, alih-alih menelusuri balik spesifikasi sebenarnya dari implementasi lalu memaksakan perbaikan
Kalimat di paragraf pertama bahwa “masalah reuse kode adalah ia menghalangi kita berubah pikiran nanti” jelas keliru
Secara umum, itu salah. Jika pikiran kita berubah dan kode sudah disalin-tempel di sepuluh tempat, kita harus memperbaiki sepuluh tempat
Sebaliknya, jika ada di dalam fungsi, kita hanya perlu mengubahnya sekali. Kalaupun ternyata satu dari sepuluh pemanggilan tidak boleh berubah, saat itu kita bisa menyalin-tempel atau membuat fungsinya lebih umum
Seperti menyeberang jalan tanpa melihat, salin-tempel hampir selalu ide buruk
Tetapi abstraksi yang buruk berujung pada pembayaran utang teknis selama berbulan-bulan
Tentu jawabannya adalah “jangan membuat abstraksi yang buruk”, tetapi kita semua tahu bagaimana itu berjalan dalam tim dan kebutuhan produk yang terus berubah
Kami punya git submodule berisi widget UI umum, dan sekarang hampir mustahil mengubah salah satunya, sehingga lebih mudah menyalin komponennya ke dalam proyek dan mengubahnya secara lokal
Ini masalah. Kode bersama harus seminimal mungkin, dan berbagi itu sendiri membuat perubahan menjadi sulit
Jika semuanya ada dalam satu fungsi, kebanyakan developer akan mencoba mengubah fungsi itu agar memenuhi semua 10 kasus. Padahal sejak awal itu seharusnya bukan satu fungsi
Jauh lebih mudah memperbaiki sepuluh tempat hasil salin-tempel daripada mengurai simpul yang salah diikat yang sudah terlanjur mengikat bagian-bagian sistem
Di permukaan, ini tampak seperti kontradiksi diri dalam topik ini, tetapi jika dibaca perlahan, ia menggunakan salin-tempel sebagai sinyal untuk mengetahui kode mana yang harus diabstraksikan, dan apa pola yang benar-benar layak diikuti
Aneh rasanya terus mengulang segala macam perintah tentang software, prinsip-prinsip yang nyaris seperti agama
Di atas kertas semuanya tampak hebat dan terasa seperti akal sehat, tetapi setelah 50 tahun pun software masih sampah dalam 90% kasus
Meski begitu, hal-hal seperti ini terus diangkat seolah-olah wawasan jenius atau peluru perak
Ada korolari yang bagus di sini. Kode buruk bertahan lama karena jauh lebih sulit dihapus