Kode murni dibaca seperti prosa yang ditulis dengan baik.
Grady Butch dalam Clean Code
Rebus sebagai kode

Apa itu rebus? Ini adalah pesan terenkripsi. Penulis rebus mengambil teks manusia biasa dan mengkodekannya menggunakan gambar, angka, dan huruf. Dan kami melihat enkripsi seperti itu dan mencoba membaca teks sumber.
Rebus memiliki dua bentuk. Di satu sisi, rebus adalah teks asli yang tidak dienkripsi, dan di sisi lain, gambar sandi. Teks adalah "apa" dari rebus, artinya, pesan. Gambar adalah "bagaimana":
bagaimana tepatnya pesan dienkripsi, dengan cara
apa . Menebak rebus, kami menerjemahkan "bagaimana" menjadi "apa".
Gambar adalah bahasa rebus, gudang persenjataan ekspresifnya. Rebusnik, seolah-olah, berbicara kepada kita dengan bantuan gambar-gambar ini, mengkomunikasikan sesuatu. Dia tidak diizinkan menggunakan kata-kata manusia normal.
Begini cara teka-teki membaca:

Kode itu seperti rebus
Kode program memiliki sesuatu yang sama dengan rebus: ia juga memiliki "apa" dan "bagaimana". Dan terkadang juga harus didekripsi.
"Apa" kode adalah tujuan, makna, efeknya, dan hasil akhir yang kita harapkan darinya.
Apa yang sebenarnya dia
lakukan .
“Bagaimana” dari kode - dengan cara konkret apa akan memenuhi “apa”, dengan penugasan, penggandaan, dan perbandingan khusus apa; implementasi algoritma, instruksi ke prosesor. Ini adalah bahasa kode yang diizinkan, gudang persenjataan ekspresifnya.
Martin Fowler membicarakannya dengan cara ini (
"Function Length" ,
original ):
Smalltalk pada tahun-tahun itu bekerja pada mesin hitam dan putih. Jika Anda perlu menyorot teks atau gambar, Anda harus membalikkan video. Kelas di Smalltalk, yang bertanggung jawab atas jadwal, berisi metode 'highlight', dan dalam implementasinya hanya ada satu baris - panggilan ke metode 'terbalik'. Nama metode itu lebih panjang daripada implementasi, tetapi itu tidak masalah, karena ada jarak yang besar antara niat dan implementasi kode ini.
Sorot di sini adalah "apa". Dalam terminologi Martin -
niat : "sorot bagian gambar." Nama ini mengungkapkan apa fungsi ini. Reverse adalah bagaimana,
implementasi .
Bagaimana tepatnya penyorotan dilakukan (menggunakan inversi gambar). Itulah perbedaan antara "apa" dan "bagaimana."
Terlepas dari kenyataan bahwa nama metode lebih panjang daripada implementasinya, keberadaan metode seperti itu masuk akal karena alasan yang sangat sederhana. Ketika kita melihat panggilan balik dalam kode, kita harus memahami atau mengingat bahwa inversi gambar digunakan untuk membuat gambar ini lebih terlihat. Saat kami melihat highlight, kami hanya membaca: "buat fragmen ini lebih terlihat." Dalam kasus pertama, kami menghabiskan sedikit upaya mental untuk memahami misi yang diberikan pada kode, di yang kedua - tidak. Dalam kasus pertama, kita melihat rebus di depan kita, membutuhkan dekripsi, di yang kedua - sebuah cerita dalam bahasa yang bisa dimengerti.
Seorang programmer, ketika dia menulis sebuah program, seperti rebus. Programmer mengenkripsi deskripsi manusia dari algoritma menggunakan alat bahasa pemrograman yang tersedia (lebih primitif daripada bahasa manusia). Mengenkripsi “apa” dengan “bagaimana”. Dan kemudian, ia atau koleganya membaca kode, menguraikan
rebus ini deskripsi awal algoritma.
Jika dalam proses membaca kode kita tidak dapat segera memahami apa hasil pelaksanaan setiap fragmen akan mengarah, yaitu, apa tujuan, makna kode, maka kode ini adalah rebus, dan perlu ditulis ulang dalam bahasa yang jelas.Masalah dengan teka-teki dalam kode adalah bahwa mereka
selalu membutuhkan upaya mental. Sekalipun kita tidak melaksanakan serangkaian operasi dekripsi dalam pikiran kita, tetapi hanya dengan bodohnya mengingat arti dari beberapa rebus, itu akan tetap menciptakan beban: pertama, untuk mengingat maknanya, dan kedua, pada saat merekam transformasi rebus dalam nilai ini.
Menguraikan rebus ketika Anda membaca kode adalah transformasi mental yang dibicarakan Tim Ottinger dalam buku Clean Code. Benar, di sana ia membahasnya dalam konteks pemberian nama yang dapat dipahami ke variabel, tetapi masalahnya dipengaruhi oleh hal yang persis sama. Kata untuk tim:
Sebagai aturan, programmer sangat cerdas. Dan orang-orang pintar kadang-kadang suka menunjukkan kekuatan kecerdasan, menunjukkan kemampuan mereka untuk menyulap mental. Pada akhirnya, jika Anda ingat bahwa variabel r berisi URL dengan host jarak jauh dan skema yang dikonversi ke huruf kecil, ini jelas menunjukkan pikiran Anda.
Salah satu perbedaan antara programmer yang cerdas dan profesional adalah bahwa seorang profesional mengerti: kejelasan adalah yang terpenting. Profesional menggunakan kekuatan mereka untuk kebaikan dan menulis kode yang dapat dimengerti oleh orang lain.
Bahkan beban kecil dari setiap rebus dapat berubah menjadi masalah jika ada banyak rebus semacam itu. Anda mungkin menemukan kode yang bacaannya sangat melelahkan.
Ketahui: rebuses dalam kode harus disalahkan atas kelelahan Anda. Rebus memperburuk kelelahan bahkan penulis sendiri secara langsung dalam proses penulisan kode. Lagi pula, saat menulis kode, programmer juga terus membaca ulang apa yang ditulis. Terlepas dari kenyataan bahwa penulis tidak mendekripsi teka-teki sendiri, tetapi hanya ingat, mereka masih membuat beban. Perangkapnya adalah bahwa
penulis tidak melihat teka-teki dalam kode sendiri ! Coba bayangkan berapa banyak upaya mental yang bisa Anda hemat di malam hari, jika Anda mulai menyingkirkan teka-teki dalam kode Anda di pagi hari!
Jadi, untuk mengurangi kelelahan dari menulis dan membaca kode, Anda harus menghindari teka-teki. Tetapi bagaimana cara melakukannya?
Bahasa kode. Kekuatan Identifier
Saya setuju dengan pernyataan Grady Butch bahwa kode bersih dibaca seperti prosa yang bagus. Ini adalah kondisi yang diperlukan, meskipun tidak mencukupi. Sebagian besar dari kita akan secara intuitif memahami apa yang dipertaruhkan, tetapi saya ingin mendapatkan setidaknya beberapa definisi: apa itu - prosa yang bagus.
Saya bertanya kepada sesama penulis: bagaimana prosa yang baik berbeda dari prosa yang buruk? Semua orang menjawab secara berbeda, tetapi entah bagaimana menekankan pentingnya bahasa: itu harus kaya, itu harus membuat gambar yang jelas dalam pikiran dan jiwa pembaca. Ketika pembaca dengan mudah memiliki gambaran yang jelas bahwa penulis ingin menggambar untuknya, kita berhadapan dengan prosa yang baik.
Kode memberi tahu prosesor apa yang harus dilakukan. Kode yang baik pada saat yang sama memberi tahu programmer - dan, lebih lagi, sangat jujur! - apa yang dia lakukan di sini. Artinya, ia menetapkan algoritme sedekat mungkin dengan bagaimana penulis sendiri akan melakukannya dalam bahasa alami. Kode kita harus melakukan ini dengan sangat baik, jika tidak, seorang
maniak yang tidak
terkendali dengan gergaji atau senapan dapat datang ke rumah kita. Kode tidak boleh berupa rebus.
Alat apa yang dimiliki kode agar tidak menjadi rebus?
Sebuah cerita atas nama kode akan mudah dipahami oleh seseorang jika kode itu sendiri berbicara dalam bahasa manusia. Ini dapat dicapai hanya dengan bantuan pengidentifikasi: nama fungsi, kelas, variabel dan konstanta - karena
hanya dalam pengidentifikasi kita dapat menggunakan kata-kata dari bahasa manusia yang kita butuhkan .
Tentu saja, kata kunci dari bahasa pemrograman juga kata-kata manusia, tetapi kosakata mereka terlalu buruk. Sesuatu seperti bahasa Ellochka the Ogre - Anda tidak dapat menulis prosa yang bagus tentangnya.
Oleh karena itu, sangat penting bahwa kode program berisi sebanyak mungkin pengidentifikasi yang dipilih dengan benar. Sehingga keseluruhan mereka membentuk prosa yang ditulis dengan sangat baik.
Lihat betapa mudahnya membaca baris kode ketika nama variabel dan metode dipilih dengan baik:
pageData.hasAttribute("Test") dom_tree.to_html() emails_str.split(',')
Melihat frasa singkat ini, mudah untuk memahami apa yang mereka bicarakan. Kami tahu hasil apa yang kami dapatkan, karena pengidentifikasi memberi tahu kami tentang hal itu. Sekarang bayangkan bahwa di tempat setiap panggilan tersebut adalah implementasinya - berapa banyak kecepatan membaca kode "terenkripsi" tersebut berkurang?
Banyak teknik refactoring paling sederhana: konstanta bernama, memilih metode, mengganti variabel dengan pemanggilan metode, variabel penjelas, memecah variabel sementara, dll. Semua tentang
bagaimana membuat kode berbicara bahasa manusia, dengan kata lain, bagaimana menghindari teka-teki .
Metode rebus
Ketika saya membaca Pure Code, saya secara berkala dikunjungi oleh pikiran: "Apa-apaan!".
Dari puncak 40 tahun pengalamannya, Robert Martin memberi kami tips tentang cara membuat kode lebih baik. Sebagai contoh:
Aturan pertama: fungsi harus kompak. Aturan kedua: fungsi harus lebih kompak.
Dan kemudian dia mengakui bahwa dia tidak dapat membuktikan klaimnya secara ilmiah. Jujur, tidak ilmiah, dia juga melakukan yang buruk. Persyaratan untuk kekompakan fungsi sudah mulai terlihat seperti dogma - itu sebabnya
perdebatan tentang panjang fungsi belum mereda selama beberapa dekade.
Dan Bob juga menawarkan untuk menulis setiap fungsi sehingga hanya melakukan satu operasi. Selain itu, apa operasi yang satu ini - juga tidak terlalu jelas. Kita harus meminta bantuan prinsip tingkat abstraksi tunggal, yang selanjutnya membingungkan situasi. Semua ini terlalu berkabut.
Martin Fowler lebih pragmatis.
Tampak bagi saya bahwa argumen tentang pemisahan niat dan realisasi memiliki lebih banyak makna. Jika, melihat sebuah fragmen kode, Anda perlu berusaha memahami apa yang dilakukannya, maka Anda perlu memasukkannya ke dalam suatu fungsi dan memberinya nama sesuai dengan "apa" ini. Maka pada saat tujuan fungsi akan segera jelas, dan dalam kebanyakan kasus Anda tidak akan peduli tentang bagaimana fungsi melakukan tugasnya.
AsliNamun, argumen yang paling masuk akal bagi saya adalah pemisahan antara niat dan implementasi. Jika Anda harus berusaha keras untuk melihat fragmen kode untuk mencari tahu apa yang dilakukannya, maka Anda harus mengekstraknya menjadi fungsi dan beri nama fungsi setelah itu "apa". Dengan begitu ketika Anda membacanya lagi, tujuan fungsi melompat keluar pada Anda, dan sebagian besar waktu Anda tidak perlu peduli tentang bagaimana fungsi memenuhi tujuannya - yang merupakan tubuh fungsi.
Sudah lebih baik. Anda lihat sekarang apa yang ingin dikatakan Martin dalam bagian ini? Maksudnya: mari kita hilangkan teka-teki. Biarkan kode itu sendiri memberi tahu kami apa hasilnya, dan bagaimana - biarkan disembunyikan di suatu tempat lebih jauh, dalam definisi fungsi. Biarkan semua teka-teki didekripsi. Tidak ada teka-teki - tidak ada usaha.
Dalam hal apa pun Anda tidak boleh secara buta menerapkan metode refactoring. Ini sangat jelas, tetapi bagaimana memahami kapan refactoring benar-benar dibutuhkan, dan kapan tidak?
Metode rebus mengatakan: jika setelah refactoring, rebus tidak hilang, maka refactoring tidak diperlukan .
Jika Anda tidak dapat menemukan nama untuk fungsi baru yang akan dengan jelas menjelaskan apa yang terjadi di dalamnya, itu adalah lonceng bahwa Anda melakukan sesuatu yang salah di sini. Cobalah untuk memilih fragmen kode yang sedikit berbeda ke dalam fungsi - yang Anda dapat dengan cepat menemukan nama yang dapat dimengerti dan pendek.Contoh decoding puzzle dalam kode (tidak terlalu berhasil)
Karena itu, saya akan mengutip sebuah fragmen dari buku "Kode Bersih" yang saya sukai. Sebelum refactoring, kami melihat kode penuh teka-teki. Refactoring dilakukan oleh penulis buku sesuai dengan aturan kode yang baik yang dipromosikan olehnya, dan - hanya kebetulan - kode refactored persis seperti kode di mana rebus didekripsi.
Penulis refactoring sepenuhnya menerapkan pengenal yang dapat dibaca manusia (nama kelas, metode, dan variabel) untuk menunjukkan apa yang sebenarnya dilakukan kode. Sangat disayangkan bahwa tidak di mana-mana ternyata berhasil, dan di beberapa tempat teka-teki baru muncul bukan teka-teki sebelumnya.
Misalnya, metode sertakan yang paling umum digunakan dalam bagian ini
private void include(String pageName, String arg) throws Exception { WikiPage inheritedPage = findInheritedPage(pageName); if (inheritedPage != null) { String pagePathName = getPathNameForPage(inheritedPage); buildIncludeDirective(pagePathName, arg); } }
Nama itu sama sekali tidak mencerminkan apa yang terjadi dalam implementasi. Termasuk apa dan dimana?
Melihat panggilan ke metode ini:
include("TearDown", "-teardown");
tidak mungkin untuk mengatakan hasil apa yang akan dicapai oleh pembuat kode di sini.
Berikutnya: apa yang dilakukan buildIncludeDirective? Dilihat dari namanya, ia harus menyusun semacam arahan inklusi, dan jadi apa? Bawa dia kembali? Tapi tidak. Dia segera menambahkannya ke hasil keseluruhan.
Dan berikut ini adalah updatePageContent. Apa yang dikatakan updatePageContent tentang hasil apa yang kita dapatkan setelah memanggil metode? Tidak ada Beberapa konten halaman di sana akan diganti oleh tidak ada yang tahu apa. Mengapa refactoring yang disebut metode ekstraksi dilakukan di sini? Apakah dia membantu menyingkirkan rebus? Itu tidak membantu, tetapi hanya lebih membingungkan kodenya. Di sini kita memiliki kasus di mana tubuh metode lebih disukai. Konstruksi
pageData.setContent(newPageContent.toString());
jauh lebih jelas daripada updatePageContent ().
Sebagai hiburan, saya sarankan pembaca untuk mencari tempat buruk lain yang ada dalam
kode refactored .
Untuk membenarkan Bob, saya dapat mengatakan bahwa kode ini tidak lagi dalam versi FitNesse saat ini. Rupanya, pada gilirannya, dia juga pernah di refactored.
Kesimpulan
Panjang fungsi adalah kriteria yang terlalu kabur untuk menentukan kualitas fungsi. "Fungsi pendek" tidak sama dengan "fungsi yang baik". Panjang fungsi bukan kriteria, lupakan semuanya.
Kode yang baik harus memberikan jawaban untuk pertanyaan programmer - mengapa dia (kode) di sini, apa yang
dia lakukan di sini,
dia mencapai hasil. Jawaban ini hanya dapat diberikan menggunakan pengidentifikasi.
Sebagai contoh jawaban seperti apa yang tidak boleh diberikan oleh kode, saya ingin memberikan kutipan dari satu buku yang menyenangkan.
"Aku Ronan, Victor of Evil," katanya perlahan. - Dan ini Tarl. Kami menginginkanmu
ajukan pertanyaan. Jika kamu berbohong, kamu mati. Mengerti
"Aku, paman, selamanya," desahnya. - Tolong. Saya akan mengatakan itu semua.
"Itu bagus," Ronan melanjutkan. - Nama?
- Ronan, Pemenang Kejahatan.
- Ya, bukan milikku, bodoh!
"Ah, ya, lalu Tarle," jawab orc dengan nada meminta maaf.
- Dan bukan milikku! Tarle bergumam. - Nama Anda, klub! Nama depan!
"Nama itu nama yang aku gunakan untuk membedakan diriku dari orang lain," gumam orc.
- Nah, beri nama ini di sini! Teriak Tarle.
Orka tiba-tiba sadar.
- Ah! Jerawat!
"Jadi, Jerawat, apa yang kamu lakukan di sini?"
"Aku menaruhnya di celanaku," datang jawaban yang jujur.
Ronan mengerutkan hidungnya dengan jijik.
"Tidak, aku bertanya apa yang dilakukan geng Orc-mu di sini!"
Mata Pimple dengan cepat berbalik, memandang sekeliling tempat kejadian.
"Kebanyakan orang tanpa kepala di sini," gumamnya.
Tarle menyentuh bahu Ronan.
"Biarkan aku mencoba," katanya dengan percaya diri dan berbalik ke orc yang ketakutan. - Katakan padaku,
Jerawat, "lanjutnya," mengapa kamu ada di sini? "
- Oh, paman, dan jangan tanya. Filosofi eksistensial bagi saya hanyalah hutan yang gelap.
"Dengar, kau sendawa naga," geramnya pelan. - Geng orcmu punya spesial
alasan untuk datang ke sini. Apa itu, di hutan?
- Ada banyak pohon.
Mata Ronan melotot, dan Tarle berbalik. Jerawat, merasa bahwa itu tidak memberikan jawaban yang diharapkan, mulai bergumam lebih lanjut.
- Dan jika Anda ingin tahu alasannya, dan bukan tentang hutan, itu semua karena orang di pub itu
membayar kami untuk datang ke sini dan membunuhmu.
James Bibby, Ronan si Barbar