Saya memutuskan untuk menulis ringkasan buku, yang diketahui semua orang, dan penulis menyebutnya "Sekolah Guru Kode Murni." Tatapan Martin tampaknya mengatakan:
"Aku melihat menembus dirimu. Apakah Anda tidak mengikuti prinsip-prinsip kode bersih lagi? "

Bab 1. Kode Bersih
Apa kode versi Martin terbersih ini dalam beberapa kata? Ini adalah kode tanpa duplikasi, dengan jumlah entitas minimum, mudah dibaca, sederhana. Sebagai moto, orang dapat memilih: "Kejelasan di atas segalanya!".
Bagian 2. Nama Yang Berarti
Nama harus menyampaikan maksud programmer
Nama variabel, fungsi, atau kelas harus menunjukkan mengapa variabel ini ada, apa fungsinya, dan bagaimana variabel itu digunakan. Jika nama memerlukan komentar tambahan, maka itu tidak menyampaikan maksud programmer. Lebih baik menulis apa yang diukur dan unit mana.
Contoh nama variabel yang bagus: daysSinceCreation;
Tujuan: menghapus ketidakjelasan.
Hindari informasi yang salah
Jangan menggunakan kata-kata dengan makna tersembunyi selain yang dimaksudkan. Waspadalah terhadap perbedaan nama yang halus. Misalnya, XYZControllerForEfficientHandlingOfStrings dan XYZControllerForEfficientStorageOfStrings.
Contoh-contoh nama informasi yang benar-benar menakutkan ditemukan ketika menggunakan huruf kecil "L" dan huruf kapital "O" dalam nama-nama variabel, terutama dalam kombinasi. Secara alami, masalah timbul karena fakta bahwa huruf-huruf ini hampir tidak berbeda dari konstanta "1" dan "0", masing-masing.
Gunakan perbedaan yang bermakna
Jika namanya berbeda, maka mereka harus menunjukkan konsep yang berbeda.
"Nomor seri" dari formulir (a1, a2, ... aN) adalah kebalikan dari penamaan yang disadari. Mereka tidak membawa informasi dan tidak memberikan gagasan tentang niat penulis.
Kata-kata yang tidak informatif itu berlebihan. Variabel kata tidak boleh muncul dalam nama variabel. Tabel kata tidak boleh muncul dalam nama tabel. Mengapa NameString lebih baik daripada Name? Bisakah sebuah nama, katakanlah, bilangan real?
Gunakan nama ejaan: generationTimestamp jauh lebih baik daripada genymdhms.
Pilih nama yang bisa dicari
Nama huruf tunggal hanya dapat digunakan untuk variabel lokal dalam metode singkat.
Hindari skema kode nama
Sebagai aturan, nama kode diucapkan dengan buruk dan mudah untuk membuat kesalahan ketik di dalamnya.
Antarmuka dan Implementasi
Saya (penulis buku) lebih suka meninggalkan nama antarmuka tanpa awalan. Awalan I, sangat umum dalam kode lama, paling mengalihkan perhatian, dan paling buruk - menyampaikan informasi yang tidak perlu. Saya tidak akan memberi tahu pengguna saya bahwa mereka berurusan dengan antarmuka.
Nama kelas
Nama kelas dan objek harus berupa kata benda dan kombinasinya: Pelanggan, WikiPage, Akun, dan AddressParser. Hindari menggunakan kata-kata seperti Manajer, Prosesor, Data, atau Info dalam nama kelas. Nama kelas tidak harus berupa kata kerja.
Nama Metode
Nama metode adalah kata kerja atau frasa verbal: postPayment, deletePage, save, dll. Metode baca / tulis dan predikat dibentuk dari nilai dan awalan dapatkan, atur dan sesuai dengan standar javabean.
Menahan diri dari permainan kata-kata
Tugas penulis adalah membuat kode-nya sejelas mungkin. Sekilas kode harus dipahami, tanpa memerlukan studi yang cermat. Fokus pada model sastra populer, di mana penulis sendiri harus bebas mengekspresikan pemikirannya.
Tambahkan konteks yang bermakna.
Konteks dapat ditambahkan menggunakan awalan: addrFirstName, addrLastName, addrState, dll. Setidaknya pembaca kode akan mengerti bahwa variabel adalah bagian dari struktur yang lebih besar. Tentu saja, akan lebih tepat untuk membuat kelas yang disebut Alamat, sehingga bahkan kompiler tahu bahwa variabel adalah bagian dari sesuatu yang lebih.
Variabel dengan konteks yang tidak jelas:
private void printGuessStatistics(char candidate, int count) { String number; String verb; String pluralModifier; if (count == 0) { number = "no"; verb = "are"; pluralModifier = "s"; } else if (count == 1) { number = ~_~quot quot~_~; verb = "is"; pluralModifier = ""; } else { number = Integer.toString(count); verb = "are"; pluralModifier = "s"; } String guessMessage = String.format( "There %s %s %s%s", verb, number, candidate, pluralModifier ); print(guessMessage); }
Fungsinya agak panjang, dan variabel digunakan di seluruh. Untuk membagi fungsi menjadi fragmen semantik yang lebih kecil, Anda harus membuat kelas GuessStatisticsMessage dan membuat tiga variabel bidang dari kelas ini. Dengan cara ini, kami akan memberikan konteks yang jelas untuk ketiga variabel - sekarang sangat jelas bahwa variabel ini adalah bagian dari GuessStatisticsMessage.
Variabel dengan konteks:
public class GuessStatisticsMessage { private String number; private String verb; private String pluralModifier; public String make(char candidate, int count) { createPluralDependentMessageParts(count); return String.format( "There %s %s %s%s", verb, number, candidate, pluralModifier ); } private void createPluralDependentMessageParts(int count) { if (count == 0) { thereAreNoLetters(); } else if (count == 1) { thereIsOneLetter(); } else { thereAreManyLetters(count); } } private void thereAreManyLetters(int count) { number = Integer.toString(count); verb = "are"; pluralModifier = "s"; } private void thereIsOneLetter() { number = ~_~quot quot~_~; verb = "is"; pluralModifier = ""; } private void thereAreNoLetters() { number = "no"; verb = "are"; pluralModifier = "s"; } }
Jangan tambahkan konteks yang berlebihan
Nama pendek biasanya lebih baik daripada nama panjang, jika hanya artinya jelas bagi pembaca kode. Jangan memasukkan lebih banyak konteks daripada yang diperlukan dalam nama.
Bab 3. Fungsi
Kompak!
Aturan pertama: fungsi harus kompak.
Aturan kedua: fungsi harus lebih kompak.
Pengalaman praktis saya telah mengajari saya (dengan biaya banyak trial and error) bahwa fungsinya harus sangat kecil. Diinginkan bahwa panjang fungsi tidak melebihi 20 garis.
Aturan satu operasi
Suatu fungsi harus melakukan hanya satu operasi. Dia harus melakukannya dengan baik. Dan dia seharusnya tidak melakukan hal lain. Jika suatu fungsi hanya melakukan tindakan-tindakan yang pada tingkat yang sama di bawah nama fungsi yang dinyatakan, maka fungsi ini melakukan satu operasi.
Bagian Fungsi
Fungsi yang melakukan hanya satu operasi tidak dapat secara bermakna dibagi menjadi beberapa bagian.
Satu tingkat abstraksi per fungsi
Untuk memastikan bahwa fungsi melakukan "hanya satu operasi", perlu untuk memverifikasi bahwa semua perintah fungsi berada pada tingkat abstraksi yang sama.
Memadukan tingkat abstraksi dalam suatu fungsi selalu menciptakan kebingungan.
Membaca kode dari atas ke bawah: aturan downgrade
Kode harus dibaca seperti cerita - dari atas ke bawah.
Setiap fungsi harus diikuti oleh fungsi-fungsi tingkat abstraksi selanjutnya. Ini memungkinkan Anda membaca kode, secara berurutan menurunkan tingkat abstraksi saat membaca daftar fungsi. Saya menyebut pendekatan ini "aturan downgrade."
Ganti perintah
Menulis perintah sakelar ringkas cukup sulit. Bahkan perintah sakelar dengan hanya dua kondisi membutuhkan lebih banyak ruang daripada satu blok atau fungsi yang harus ditempati dalam pandangan saya. Juga sulit untuk membuat perintah switch yang melakukan satu hal - pada dasarnya, perintah switch selalu melakukan operasi N. Sayangnya, kami tidak dapat melakukan tanpa selalu beralih perintah, tetapi setidaknya kami dapat memastikan bahwa perintah ini tersembunyi di kelas tingkat rendah dan tidak diduplikasi dalam kode. Dan tentu saja, polimorfisme dapat membantu kita dengan ini.
Contoh ini hanya menunjukkan satu operasi, tergantung pada jenis karyawan.
public Money calculatePay(Employee e) throws InvalidEmployeeType { switch (e.type) { case COMMISSIONED: return calculateCommissionedPay(e); case HOURLY: return calculateHourlyPay(e); case SALARIED: return calculateSalariedPay(e); default: throw new InvalidEmployeeType(e.type); } }
Fitur ini memiliki beberapa kelemahan. Pertama, ini luar biasa, dan dengan penambahan jenis pekerja baru akan tumbuh. Kedua, itu paling jelas melakukan lebih dari satu operasi. Ketiga, melanggar prinsip tanggung jawab tunggal, karena memiliki beberapa kemungkinan alasan untuk perubahan.
Keempat, itu melanggar Prinsip Tertutup Terbuka, karena kode fungsi harus berubah setiap kali tipe baru ditambahkan.
Tetapi mungkin kelemahan yang paling serius adalah bahwa program tersebut mungkin mengandung banyak fungsi lain yang tidak terbatas dengan struktur yang serupa, misalnya:
isPayday (Karyawan e, Tanggal tanggal)
atau
deliverPay (Karyawan e, Pembayaran uang)
dan sebagainya.
Semua fungsi ini akan memiliki struktur cacat yang sama. Solusi untuk masalah ini adalah mengubur perintah sakelar di dasar pabrik abstrak dan tidak menunjukkannya kepada siapa pun. Pabrik menggunakan perintah sakelar untuk membuat turunan yang sesuai dari keturunan Karyawan, dan panggilan ke fungsi calculPay, isPayDay, deliverPay, dll., Meneruskan transfer polimorfik melalui antarmuka Karyawan.
public abstract class Employee { public abstract boolean isPayday(); public abstract Money calculatePay(); public abstract void deliverPay(Money pay); } ----------------- public interface EmployeeFactory { public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType; } ----------------- public class EmployeeFactoryImpl implements EmployeeFactory { public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType { switch (r.type) { case COMMISSIONED: return new CommissionedEmployee(r) ; case HOURLY: return new HourlyEmployee(r); case SALARIED: return new SalariedEmploye(r); default: throw new InvalidEmployeeType(r.type); } } }
Aturan umum saya mengenai perintah sakelar adalah bahwa perintah ini sah jika mereka muncul sekali dalam program, digunakan untuk membuat objek polimorfik, dan bersembunyi di balik hubungan pewarisan untuk tetap tidak terlihat oleh bagian lain dari sistem. Tentu saja, tidak ada aturan tanpa pengecualian, dan dalam beberapa situasi perlu untuk melanggar satu atau lebih ketentuan dari aturan ini.
Gunakan nama yang bermakna
Setengah dari upaya untuk menerapkan prinsip ini adalah memilih nama-nama bagus untuk fungsi-fungsi ringkas yang melakukan operasi tunggal. Semakin kecil dan lebih khusus fungsinya, semakin mudah untuk memilih nama yang bermakna untuknya.
Jangan takut untuk menggunakan nama yang panjang. Nama yang panjang dan bermakna lebih baik daripada yang pendek dan tidak jelas. Pilih skema yang membuatnya mudah untuk membaca kata-kata dalam nama fungsi, dan kemudian buat nama dari kata-kata ini yang menjelaskan tujuan dari fungsi tersebut.
Argumen fungsi
Dalam kasus ideal, jumlah argumen fungsi adalah nol. Berikut ini adalah fungsi dengan satu argumen (unary) dan dengan dua argumen (binary). Fungsi dengan tiga argumen (ternary) harus dihindari sedapat mungkin.
Argumen output membingungkan situasi bahkan lebih cepat daripada input. Sebagai aturan, tidak ada yang mengharapkan fungsi untuk mengembalikan informasi dalam argumen. Jika Anda tidak dapat mengelola tanpa argumen, cobalah setidaknya membatasi diri Anda pada satu argumen input.
Konversi yang menggunakan argumen keluaran alih-alih nilai balik membingungkan pembaca. Jika fungsi mengubah argumen inputnya, maka hasilnya
harus diberikan nilai pengembalian.
Argumen Bendera
Argumen argumennya jelek. Melewati makna logis dari suatu fungsi adalah kebiasaan yang benar-benar mengerikan. Ini segera merumitkan tanda tangan metode, dengan keras menyatakan bahwa fungsi melakukan lebih dari satu operasi. Jika bendera benar, satu operasi dilakukan, dan jika salah, yang lain.
Fungsi biner
Fungsi dengan dua argumen lebih sulit dipahami daripada fungsi unary. Tentu saja, dalam beberapa situasi, bentuk dua argumen sesuai. Misalnya, memanggil Point p = Point baru (0,0); sangat masuk akal. Namun, dua argumen dalam kasus kami adalah komponen yang dipesan dengan nilai yang sama.
Objek sebagai Argumen
Jika suatu fungsi harus menerima lebih dari dua atau tiga argumen, sangat mungkin bahwa beberapa argumen ini harus dikemas dalam kelas yang terpisah. Pertimbangkan dua deklarasi berikut:
Circle makeCircle(double x, double y, double radius); Circle makeCircle(Point center, double radius);
Jika variabel ditransfer bersama-sama secara keseluruhan (seperti variabel x dan y dalam contoh ini), maka, kemungkinan besar, bersama-sama mereka membentuk konsep yang pantas namanya sendiri.
Kata Kerja dan Kata Kunci
Memilih nama yang baik untuk suatu fungsi sebagian besar dapat menjelaskan arti dari fungsi tersebut, serta urutan dan makna argumennya. Dalam fungsi unary, fungsi itu sendiri dan argumennya harus membentuk pasangan kata kerja / kata benda alami. Misalnya, panggilan dari form tulis (nama) terlihat sangat informatif.
Pembaca memahami bahwa tidak peduli apa "nama" itu, itu adalah suatu tempat "tertulis". Bahkan lebih baik adalah catatan writeField (nama), yang melaporkan bahwa "nama" ditulis ke "bidang" dari beberapa struktur.
Entri terakhir adalah contoh menggunakan kata kunci dalam nama fungsi. Dalam formulir ini, nama argumen dikodekan dalam nama fungsi. Misalnya, assertEquals dapat ditulis sebagai assertExpectedEqualsActual (diharapkan, aktual). Ini sebagian besar memecahkan masalah mengingat urutan argumen.
Pemisahan perintah dan permintaan
Suatu fungsi harus melakukan sesuatu atau menjawab beberapa pertanyaan, tetapi tidak secara bersamaan. Entah fungsi mengubah keadaan objek, atau mengembalikan informasi tentang objek ini. Menggabungkan dua operasi seringkali menciptakan kebingungan.
Pisahkan blok coba / tangkap
Blok coba / tangkap terlihat sangat jelek. Mereka membingungkan struktur kode dan penanganan kesalahan campuran dengan pemrosesan normal. Untuk alasan ini, badan blok coba dan tangkap direkomendasikan untuk dialokasikan dalam fungsi yang terpisah.
Kesalahan penanganan sebagai satu operasi
Fungsi harus melakukan satu operasi. Penanganan kesalahan adalah satu operasi. Ini berarti bahwa fungsi yang memproses kesalahan tidak boleh melakukan hal lain. Oleh karena itu, jika kata kunci coba hadir dalam fungsi, maka itu harus menjadi kata pertama dalam fungsi, dan setelah menangkap / akhirnya memblokir tidak ada yang lain.
Ini menyimpulkan Bab 3.