- Alih-alih memisahkan tingkat abstraksi dengan membaginya menjadi fungsi-fungsi kecil, ada pandangan bahwa kode linear yang mengalir dari atas ke bawah lebih mudah diikuti untuk memahami keseluruhan alurnya
- Jika struktur top-down dibentuk lewat ekstraksi fungsi, kita mungkin harus bolak-balik memeriksa antar fungsi dengan nama mirip seperti
bakedanbakePizza - Hal-hal seperti lokasi pemanasan awal oven atau hasil saat pizza yang sama dimasukkan dua kali bisa membuat fungsi kecil, alih-alih memperjelas niat, justru menyembunyikan perilaku nyata
- Jika kode linear diberi komentar per langkah, niat pekerjaan bisa dijelaskan tanpa menambah referensi tidak langsung, sehingga bisa lebih mudah dibaca daripada menambah abstraksi
- Mengekstrak fungsi kecil yang hanya dipakai sekali menyebabkan hilangnya linearitas, dan seperti pada contoh cara pembuatan oven, di kode nyata hal ini bahkan bisa memperlihatkan masalah performa
Saat linearitas lebih penting daripada ekstraksi fungsi
- Contoh dari Google Testing Blog membandingkan dua implementasi
createPizza, dan menilai implementasi di kanan lebih mudah dibaca serta top-down karena tidak mencampur tingkat abstraksi - Dari sudut pandang sebaliknya, yang lebih penting adalah bahwa implementasi di kiri merupakan kode yang bisa dibaca secara linear dari atas ke bawah layar
- Untuk memahami keseluruhan perilaku pada implementasi kanan, pembaca harus berpindah ke beberapa definisi fungsi kecil
- Dari cara penyajiannya juga, sebagian kode di kanan dihilangkan sehingga ukuran kedua implementasi tampak mirip, padahal sebenarnya yang kanan lebih panjang
- Ekstraksi fungsi bisa membuat perilaku sulit dipahami hanya dari namanya
- Saat ada
bakedanbakePizzasekaligus, sulit langsung tahu fungsi mana yang memanaskan oven - Untuk memastikan apakah memasukkan pizza yang sama dua kali bersifat idempoten atau justru merusak hasil, kita harus melihat implementasi internalnya
- Saat ada
Kode linear dengan komentar dan contoh oven
- Versi kode linear di kiri yang diberi komentar memakai nama fungsi dari versi kanan dinilai sebagai bentuk yang paling mudah dibaca
- Komentar seperti
Prepare pizza,Add toppings,Heat oven,Bake pizza,Box and slicemengungkapkan niat di setiap tahap - Keterbacaan tidak datang dari lapisan abstraksi tambahan dan referensi tidak langsung, melainkan dari penjelasan yang tepat tentang apa yang sedang dilakukan saat itu
- Komentar seperti
- Kesimpulannya cenderung pada gagasan agar fungsi kecil yang hanya dipakai sekali tidak diekstrak dari kode linear
- Manfaat ekstraksi fungsi kecil dianggap tidak mampu menutupi hilangnya linearitas
- Penanganan oven dalam contoh tersebut juga terasa canggung secara struktural
- Pemanasan awal oven adalah perilaku yang lengkap dengan sendirinya, sehingga lebih tepat jika menjadi metode milik oven
- Alur membuat oven baru dan memanaskannya setiap kali membuat satu pizza tidak sesuai dengan cara penggunaan yang realistis
- Struktur seperti ini juga muncul di kode nyata dan kadang bisa menimbulkan masalah performa
- Kemungkinan besar oven seharusnya diterima sebagai parameter alih-alih dibuat baru di dalam
createPizza- Penyediaan oven lebih dekat dengan tanggung jawab pemanggil
- Jika alurnya adalah memasukkan pizza ke dalam kotak, antarmuka yang mengembalikan kotak alih-alih pizza mungkin terasa lebih alami
1 komentar
Komentar Hacker News
Ini soal gaya, dan seperti memasak, terlalu banyak atau terlalu sedikit garam sama-sama bisa merusak masakan.
Saya harap tidak ada yang di sini mengusulkan satu fungsi dewa 1000 baris, dan batas maksimal 5 baris per fungsi juga tidak enak dibaca. Menentukan di mana harus memecahnya butuh penilaian, intuisi yang baik, dan iterasi. Hanya karena abstraksi pertama yang dicoba kurang bagus, bukan berarti abstraksi harus ditinggalkan; setelah beberapa kali refactoring, bisa saja muncul class dan API yang cocok dengan domain bisnis.
Pada saat yang sama, jangan terlalu tergesa-gesa membuat abstraksi atau bersikap seolah beberapa baris duplikasi adalah luka fatal. Abstraksi prematur mudah mengikat kode yang sebenarnya tidak perlu berevolusi bersama. Mengekstrak fungsi yang hanya dipanggil dari satu tempat untuk menyembunyikan satu unit kerja bisa membuat algoritme lebih rapi, dan sangat berguna terutama saat menyembunyikan boilerplate atau campuran concern infrastruktur seperti logika bisnis dan penanganan koneksi DB. Namun harus dipakai dengan hati-hati, dan sebaiknya hindari memecah langkah-langkah yang seharusnya berada pada tingkat abstraksi yang sama.
Seseorang yang pernah bekerja bersama saya mengekstrak semua kondisi boolean menjadi fungsi dengan alasan “lebih mudah dibaca”, dan sama sekali tidak menulis komentar karena “komentar itu buruk”. Saya tidak suka buku itu karena menghasilkan fanatik yang mengikuti saran buruk seperti ini secara membabi buta.
Kadang-kadang domain bisa saja membutuhkan fungsi dewa 1000 baris, dan karena logika serta pekerjaan terkumpul di satu tempat, itu bisa jauh lebih mudah dibaca daripada 20 fungsi masing-masing 50 baris. Toh untuk memahami keseluruhannya, Anda tetap harus membaca semua 20 fungsi itu, dan bisa saja ada orang yang mencoba memakai ulang sebagian di antaranya, lalu menyesuaikannya untuk 2–3 kebutuhan yang tidak ada dalam pekerjaan aslinya, dan akhirnya mengikat logika tertentu dengan use case yang tidak terkait.
Kalau fungsi itu pure function, menurut saya mau 1000 baris atau 10000 baris tetap tidak masalah dan masih baik-baik saja.
Resep masakan pun sudah sangat diabstraksikan. Saat tertulis “tumis bawang bombai sebentar”, diasumsikan Anda sudah tahu cara memotong bawang bombai dan algoritme menumis sebentar. Kalau semuanya ditulis inline, resepnya tidak akan terbaca.
Kode juga serupa. Jika abstraksi disingkirkan secara ketat, kita akan turun sampai ke level terendah yang diizinkan bahasa, dan itu jelas bukan kode yang mudah dibaca. Misalnya, jika alih-alih memakai metode
decodedi Python Anda mencoba melakukan decoding Unicode sendiri, akan sangat sulit memahami apa yang sebenarnya dilakukan program. Orang tidak melakukan itu hanya karena bahasa menyediakan abstraksi yang sederhana dan sudah teruji dengan baik; lalu apa bedanya dengan membuat abstraksi sederhana dan teruji dengan baik sendiri untuk dipakai di seluruh logika bisnis?Bagian yang sulit adalah membuat abstraksi yang dipilih dengan begitu baik sampai tidak ada orang yang perlu menyentuhnya lagi.
Hanya karena baris kode saat ini terlihat mirip, bukan berarti ke depannya harus tetap sama atau dipertahankan agar sama. Jika dua use case berbeda dipaksa digabung hanya karena “kodenya hampir berulang”, seiring waktu abstraksi itu mudah berubah menjadi abstraksi yang tidak mengabstraksikan apa pun.
Jika use case-nya terlalu menyimpang, implementasinya akan mendorong banyak logika ke sisi caller, atau mengekspos perbedaan sebagai flag sehingga di dalamnya ada dua implementasi berbeda berdampingan. Yang pertama adalah abstraksi dangkal sehingga nilainya kecil, dan yang kedua kurang jelas dibanding dua implementasi independen.
Kode contoh terlalu sederhana, jadi wajar kode linear lebih enak dibaca, tetapi idenya tidak mudah diskalakan
Reusability atau kemudahan unit test juga perlu dipertimbangkan, dan jika semua kode dimasukkan ke dalam satu fungsi, semua variabel lokal—yang bisa saja terkait atau tidak terkait dengan blok kode yang sedang dibaca—akan berada dalam scope, sehingga penalaran bisa jadi lebih sulit
Namun kalau mengingat masa ketika pengalaman saya masih sedikit, saya sering membuat kode linear yang sebenarnya baik-baik saja menjadi terlalu termodularisasi, sehingga harus melompat ke sana-sini dan justru kurang maintainable. Bentuk awal yang ditulis punya kelebihan karena lebih dekat dengan alur berpikir di kepala saat itu, dan pembaca mungkin juga lebih mungkin menafsirkannya begitu. Refactoring berlebihan bisa menghilangkan hal itu
Pada akhirnya, pemrograman lebih dekat dengan kerajinan; pengalaman membantu memilih yang tepat sesuai situasi
Tujuannya hanya satu. Pekerjaannya adalah mengubah halaman-halaman HTML individual yang dipakai di satu sudut aplikasi, pada satu platform, menjadi carousel yang meniru nuansa native platform lain, dan sangat terspesialisasi untuk platform itu serta area aplikasi tersebut
Ke-9 scope itu bisa saja dijadikan fungsi masing-masing, tetapi itu akan membuat para developer ingin me-reuse-nya. Tiap tahap punya asumsi halus tentang apa yang terjadi di tahap sebelumnya, dan untuk menjadikannya fungsi terpisah, asumsi-asumsi itu harus ditinjau ulang, digeneralisasi, dan diverifikasi bahwa tiap method bisa berjalan secara mandiri. Tidak ada alasan mengeluarkan biaya seperti itu untuk kode yang hampir tidak akan dibutuhkan di tempat lain
Debugging juga tidak lebih sulit, ada test end-to-end, dan state tahap perantara tidak bocor keluar dari fungsi. Faktanya, 2 developer lain ikut berkontribusi pada perubahan seiring waktu, semuanya berjalan baik, dan penulisannya juga cepat
Kode linear bisa diskalakan dan menyelesaikan masalah. Tidak selalu bentuk yang diinginkan, tetapi dalam lebih banyak situasi daripada yang dikira, ia membuat hidup jauh lebih mudah
Reaksi saat pertama melihat monster 2000 baris itu memang tidak bagus, tetapi setelah melihatnya 5 menit saja, sulit menemukan cacat nyata; dengan beberapa test, yang tersisa hanya ketakutan yang tidak terwujud
Pada suatu titik, orang akan sadar bahwa puluhan fungsi itu harus dipanggil dalam urutan tertentu, dan masing-masing hanya dipakai sekali. Pada akhirnya, ini sama saja memaksa siapa pun yang ingin memakai fungsi-fungsi itu secara berguna untuk mengetahui urutan kombinasi yang seperti sihir
Alasan inti mengapa fungsi linear yang besar sering kali lebih mudah dibaca dan lebih diinginkan adalah karena beberapa konsep dan relasinya bisa dipertahankan sekaligus dalam satu bongkahan tanpa context switching, sehingga membantu pemahaman. Pendukung ekstremnya adalah Arthur Whitney, penemu bahasa K, yang menulis kode sangat ringkas—hampir tidak bisa dipahami orang lain—agar sebanyak mungkin muat dalam satu layar
Sebagai contoh pribadi, membaca, memahami, dan men-debug fungsi pemroses pesan Windows raksasa, yaitu
WndProc, yang berisi business logic dalam statementswitchbesar, jauh lebih mudah dibanding versi Visual C++ yang memecah message handler menjadi fungsi terpisahAda juga kode sampel mikrokontroler: versi contoh penggunaan ADC yang semuanya ada dalam satu file, dan versi yang dibagi ke beberapa file seperti
main.c,config.c,interrupts.c,timer.c, dan sebagainya. Meski kurang dari 200 baris, versi kedua sulit dipahami karena context switchingPotongan kode seperti ini biasanya menjadi fungsi
privatedalam class, dan memiliki state. Karena fungsiprivate, praktiknya juga sulit ditesAkibatnya muncul banyak fungsi
privateyang hanya dipanggil sekali dan biasanya memodifikasi state lewat side effect. Jika masih tepat menempel pada pemanggilnya, dalam kasus sederhana masih cukup terbaca, tetapi seiring waktu seseorang menambahkan fungsi lain di antara fungsi pemanggil dan fungsi yang diekstrak ituMaka potongan-potongan kode yang tidak jelas dipanggil dari mana kecuali melihat call graph atau mencari di file class akan memodifikasi state side effect yang berbeda-beda
Jika hendak membuat kode menjadi non-linear, bila bahasanya mendukung, setidaknya saya berharap fungsi
privateyang diekstrak dipertimbangkan untuk dijadikan inner function dari fungsi pemanggil. Dengan begitu jelas bahwa ia tidak dipanggil dari tempat lainDalam codebase nyata, ini pun bukan pilihan biner, melainkan lebih mirip seni mengombinasikan keduanya agar bentuknya mudah dibaca dan maintainable
Apakah orang-orang akan menguji semua cabang itu? Atau hanya menulis test yang memasukkan satu pizza lalu sekadar melihat apakah kira-kira berjalan? Menguji banyak cabang dari luar biasanya merepotkan, dan lebih menyebalkan dibanding menguji fungsi kecil yang terspesialisasi, jadi kemungkinan besar yang terjadi adalah opsi kedua
Pernyataan bahwa “kode linear tidak dapat diskalakan” justru kebalikannya. Dalam codebase besar, yang benar-benar menjadi mimpi buruk adalah fungsi-fungsi kecil dan ringkas dengan call stack yang bertumpuk dalam
Tidak jelas di mana kode baru harus ditambahkan, dan karena harus melacak semua jalur tempat kode bisa dipanggil, tingkat kesulitan memahami dampak perubahan meningkat secara eksponensial, serta muncul subrutin yang duplikatif
Dalam 99% kasus, itu bukan abstraksi yang baik, jadi lebih baik gunakan saja kode linear. Saya lebih memilih salin/tempel daripada semantik fungsi yang meragukan
print_table()ditambahkan, seseorang akan menemukannya lalu memakainya di kodenya sendiri, kemudian menambahkan flag kecil untuk menyesuaikan output dengan use case-nyaSetelah 12 bulan, bentuknya menjadi seperti ini:
print_table(rows,headers = None,is_unicode = False,left_align = False,align = [],remove_emoji = None,max_width = 80,potato_mode = 7,_debug_frontend = not FLAGS.dont_debug,ellipsis_for = 0,no_print = False,)Jika kedua konsep ini dilihat secara ortogonal, selain fakta bahwa keterbacaan dapat memengaruhi skalabilitas, kode linear tidak diskalakan sebaik kode modular. Dikotomi ini layak diketahui dan layak dipertimbangkan bergantung pada situasinya
Meski begitu, saya tetap tidak setuju. Jika fungsi kecil itu adalah fungsi murni, ia tidak menimbulkan masalah keterbacaan. Artinya ia tidak menyentuh state, tidak menyuntikkan logika ke dalam kode, dan dependency injection serta meneruskan fungsi ke fungsi lain harus diminimalkan secara eksplisit
Jika membuat pipeline fungsi-fungsi murni yang hanya meneruskan data, kode menjadi mudah dibaca dan dapat diskalakan. Kasus ketika logika harus ditulis ulang karena cacat desain jauh berkurang, dan ketika fungsi murni dikomposisikan, kode menjadi seperti Lego. Refactoring juga lebih menyerupai menyusun ulang dan mengombinasikan kembali elemen primitif yang sudah ada
Contoh kodenya setidaknya akan kurang mengganggu jika berusaha mempertahankan metafora pizza secara bermakna, atau jika bukan kode Go berkualitas rendah
prepareadalah nama fungsi yang buruk sekali. Gopher berpengalaman mungkin akan menamainya sepertiNewPizzaFromOrderSaya tidak melihat alasan untuk menjadikan
addToppingssebagai fungsi terpisah. Jika memang perlu, secara pribadi saya akan menjadikannya method milikPizza, sepertifunc (p *Pizza) WithToppings(topping ...Topping) *Pizza { /* ... */ }. Pizza sungguhan bersifat mutable, jadi method-nya mengubah receiverSaya juga tidak paham mengapa harus menginstansiasi oven baru setiap kali memanggang pizza. Seharusnya mulai dengan oven yang sudah ada, lakukan
oven.Preheat(), lalu panggiloven.Bake(pizza). Lebih jauh lagi,oven.Preheat()bisa dibuat mengembalikan tipe baru dariOvenyang mengekspos.Bake(), sehingga kesalahan memanggang tanpa pemanasan awal dapat dicegah pada tahap kompilasi. Di tempat lain mungkin ada interfaceBaker, dan mungkin juga ada implementasiToasterOvenyang tidak memerlukannya karena pemanasan awal tidak terlalu pentingBahkan tanpa mengubah kodenya, saya akan menata ulang urutan deklarasi agar sesuai dengan alur yang dapat diprediksi. Dengan begitu, saat menelusuri fungsi-fungsi yang saling memanggil, kita tidak perlu melompat naik turun halaman
Saya tidak punya waktu, jadi berhenti di sini, tetapi kode ini sudah merupakan contoh yang terlalu buruk bahkan untuk memulai perdebatan “mana yang lebih mudah dibaca”
John Carmack juga mengatakan hal yang hampir sama, dan sejak itu saya terus mengikutinya. Kode linear secara alami mudah dibaca karena mengikuti urutan eksekusi, dan meminimalkan lompatan pandangan
Sebagian kode harus non-linear demi reuse, dan saat itu eksekusinya menjadi graf. Jika kode tidak memanfaatkan reuse berstruktur graf, tidak perlu memperkenalkan simpul di tempat yang cukup dengan satu sisi
http://number-none.com/blow/blog/programming/2014/09/26/carm...
Dalam kasus ini, akan lebih baik jika kode di kiri dibuat seperti
pizza.Toppings = get_pizza_toppings(order.kind), sehingga perubahan pada pizza tetap menjadi pusat di fungsi utamaSaya cukup setuju bahwa kode linear lebih mudah dibaca, tetapi itu saja tidak otomatis menjadikannya praktik kode yang baik
Saya menganggap kode linear yang baik memang lebih mudah dibaca, tetapi maintainability dan kemudahan pengujiannya jauh lebih rendah. Saya punya pengalaman puluhan tahun dan juga menjadi penilai eksternal untuk mahasiswa CS, dan selama bertahun-tahun satu-satunya praktik baik yang benar-benar jelas saya lihat di dunia nyata hanyalah menjaga fungsi tetap kecil
Saya juga tidak terlalu menyukai abstraksi, dan tidak berpikir duplikasi kode harus selalu dihindari, tetapi jika Anda membuat fungsi sedekat mungkin dengan satu tujuan, diri Anda di masa depan akan berterima kasih
Jika kode seperti contoh berjalan di produksi selama 10 tahun, tiap bagiannya akan berubah. Kalau beruntung, komentarnya juga akan diperbarui, tetapi kebanyakan tidak akan begitu. Unit test juga akan menjadi besar dan sulit ditangani, makin lama makin asal, dan seseorang bisa lupa memperbaiki bagian test yang tidak terlihat jelas terkait dengan perubahan. Kodenya sendiri juga kemungkinan besar akan makin kurang mudah dibaca seiring waktu. Bukan karena niat buruk atau ketidakmampuan, melainkan karena alasan manusiawi seperti tekanan waktu
Di dunia yang sempurna kita tidak perlu memisahkan concern, tetapi kita hidup di dunia yang tidak sempurna, dan semakin kecil fungsi serta semakin sedikit tanggung jawabnya, semakin mudah menangani ketidaksempurnaan itu seiring waktu
Jika sebuah objek sedang dilewatkan melalui alur state tertentu, menurut saya lebih baik memecahnya dan menandai transisi dengan tipe, atau menuliskannya sebagai satu fungsi besar. Misalnya, jika
bakePizzamenerimaRawPizzadan mengembalikanBakedPizza, urutan pemanggilan bisa dipaksakan pada compile timeKarena keterbacaan, kebenaran, dan kemudahan pengujian, saya lebih menyukai yang pertama, tetapi di sebagian besar bahasa pemrograman, untuk mengubah tipe objek Anda harus membuat objek baru dan ada biaya runtime. Jika itu hot code path, perubahan in-place masuk akal, dan dalam kasus itu lebih baik menaruhnya dalam satu fungsi linear
https://mitpress.mit.edu/9780262045490/
Email terkait dari John Carmack: http://number-none.com/blow/blog/programming/2014/09/26/carm...
Diskusi: https://news.ycombinator.com/item?id=12120752
Sangat setuju. Dulu saya berada di kubu sebaliknya
Ketegangan dasar di sini adalah antara locality of behaviour di satu sisi dan keinginan untuk menampilkan tampilan “daftar isi” tingkat tinggi dengan jelas di sisi lain. Untuk kode yang enak dibaca, locality lebih penting. Seperti yang dikatakan tulisan itu, perspektif daftar isi bisa dibuat cukup jelas dengan komentar bagian
Ada alasan yang lebih penting untuk lebih menyukai kode linear. Saat menelusuri seluruh codebase, jauh lebih mudah jika “potongan” besar—yaitu fungsi, class, atau unit yang dipaksakan bahasa—secara kasar berpadanan dengan use case bisnis. Jika tidak, ruang pencarian menjadi terlalu besar, dan Anda harus merekonstruksi sendiri keseluruhan dari potongan-potongannya. Struktur kode seharusnya melakukan pekerjaan itu untuk Anda
Jika beberapa “hal” semuanya terkait dengan satu pekerjaan, misalnya pendaftaran atau pembelian, sebaiknya semuanya juga ditempatkan sebagai satu hal di kode. Jauh lebih mudah ditemukan dan diubah. Pecah menjadi subfungsi hanya ketika reuse diperlukan, jangan memecah hanya demi organisasi
[0] https://htmx.org/essays/locality-of-behaviour/
Alasan terbesar adalah state. Semakin panjang fungsi, semakin luas scope variabel lokal. Variabel apa pun bisa diubah dari mana saja dalam fungsi, dan aliran data tidak langsung jelas. Dengan lebih banyak fungsi, scope tetap kecil dan aliran data menjadi lebih eksplisit
Efek sampingnya, indentasi juga berkurang
Pada saat yang sama, saya tidak suka fungsi yang terlalu kecil. Karena jadi sulit menemukan di mana pekerjaan sebenarnya terjadi
Bayangkan proses tutup buku harian dengan 10 langkah yang tidak bisa di-reuse dan harus dijalankan berurutan, masing-masing 100 baris. Tiap langkah memakai data yang mirip dengan langkah sebelumnya, tetapi tidak sama. Apakah Anda benar-benar akan memilih satu fungsi tunggal 1000 baris?
Keduanya terbaca secara linear. Versi yang mengekstrak fungsi-fungsi kecil punya daftar isi di bagian atas halaman dan merangkum aliran data antar langkah. Jika akan membaca semuanya, itu tampak seperti urutan baca yang menarik
Namun untuk mempertahankan keterbacaan ini, ketika urutan langkah berubah, posisi fungsi juga harus dipindahkan. Jika itu fungsi
privatedan hanya dipanggil dari daftar isi, tidak masalah. Tetapi tidak ada yang memaksa urutannya tetap terjaga, dan juga tidak ada yang memaksa orang memikirkan alur baca keseluruhanBegitu fungsi mulai di-reuse, sering kali ia tidak lagi bisa dilinearkan. Kadang orang menyerah lalu mengurutkannya secara alfabetis, atau akhirnya menjadi acak begitu saja
Berdasarkan pengalaman, semakin seseorang terbiasa dengan kode, semakin ia menganggap mendorong kode ke fungsi-fungsi kecil adalah jalan yang benar
Karena ia sudah membangun model mental untuk kode tersebut, implementasi yang paling rapi baginya adalah implementasi dengan jumlah baris yang sangat sedikit
Namun ketika orang berikutnya datang, ia harus bolak-balik ke sana kemari sambil melakukan push/pop stack di kepalanya untuk membangun model mental yang sama tanpa konteks awal, dan ini jauh lebih sulit
Misalnya, seberapa sering Anda membaca kode sumber standard library dari bahasa yang Anda gunakan? Hampir tidak pernah; biasanya Anda melihat signature metode, lalu membaca dokumentasi jika agak rumit atau baru
Inti dari antarmuka adalah membuat kita hanya perlu peduli apa yang dilakukan sebuah metode, bukan bagaimana metode itu diimplementasikan. Itu dijelaskan oleh kombinasi konteks, nama, dan dokumentasi. Namun banyak developer tidak memahami atau tidak memedulikan hal ini, sehingga menulis kode yang tidak masuk akal, entah linear maupun modular
Misalnya, jika dalam sebuah kelas service Anda harus memanggil satu metode untuk mendapatkan suatu data, metode lain untuk mendapatkan data lain, lalu metode ketiga untuk mendapatkan data yang harus digabungkan dengan dua data sebelumnya, apa sebenarnya makna service itu? Itu sama saja mengekspos seluruh kompleksitas internal ke luar
Bukan berarti kita harus memaksakan metode kecil. Dua puluh fungsi 5 baris yang hanya dipanggil sekali, mengerjakan hal yang sangat spesifik, dan harus dipanggil dalam urutan yang benar itu tidak ada artinya. Itu bukan clean code, melainkan lebih dekat ke cargo cult programming
Yang penting adalah melakukan abstraksi dengan tepat agar masuk akal bagi anggota tim baru maupun yang berpengalaman, mudah dinalar, dan kompleksitas disembunyikan di tempat yang sesuai. Tidak mudah, tetapi mungkin
Anak saya cukup cerdas, tetapi kesulitan di sekolah, dan salah satu dari beberapa ahli menjelaskan bahwa sekolah umumnya mengajar secara bottom-up, sementara anak saya adalah pembelajar yang sangat top-down. Ia perlu gambaran umum terlebih dahulu sebelum masuk ke detail, sedangkan orang lain perlu memahami detail dulu lalu menyusun gambaran besarnya. Sekolah biasanya mengajar sesuai kelompok kedua
Mungkin ada perbedaan serupa di antara para programmer
Jika developer sebelumnya menulis fungsi
BakePizza, Anda cukup mengasumsikan pizza akan dipanggang dengan benar lalu lanjut ke baris berikutnya. Jika saat mencoba memahami cara kerja restoran Anda malah tenggelam dalam detail seperti suhu oven, Anda tidak akan memahami bagaimana restoran berjalan dan juga akan lupa suhu oven yang tepatEditor harus punya toggle untuk melakukan inline sementara pada fungsi. Tidak perlu lagi bolak-balik