Untuk menghindari angka ajaib, kita sering mendengar bahwa kita harus memberikan nama yang bermakna secara literal. Seperti:
//THIS CODE COMES FROM THE CLEAN CODE BOOK
for (int j = 0; j < 34; j++) {
s += (t[j] * 4) / 5;
}
-------------------- Change to --------------------
int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j = 0; j < NUMBER_OF_TASKS; j++) {
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
Saya punya metode dummy seperti ini:
Jelaskan: Saya kira saya memiliki daftar orang untuk dilayani dan secara default, kita menghabiskan $ 5 untuk membeli makanan saja, tetapi ketika kita memiliki lebih dari satu orang, kita perlu membeli air dan makanan, kita harus menghabiskan lebih banyak uang, mungkin $ 6. Saya akan mengubah kode saya, tolong fokus pada literal 1 , pertanyaan saya tentang itu.
public int getMoneyByPersons(){
if(persons.size() == 1){
// TODO - return money for one person
} else {
// TODO - calculate and return money for people.
}
}
Ketika saya meminta teman saya untuk meninjau kode saya, yang satu mengatakan memberi nama untuk nilai 1 akan menghasilkan kode yang lebih bersih, dan yang lain mengatakan kita tidak perlu nama konstan di sini karena nilainya bermakna dengan sendirinya.
Jadi, pertanyaan saya adalah Haruskah saya memberi nama untuk nilai literal 1? Kapan nilai merupakan angka ajaib dan kapan bukan? Bagaimana saya membedakan konteks untuk memilih solusi terbaik?
sumber
persons
dan apa yang digambarkannya? Kode Anda tidak memiliki komentar apa pun sehingga sulit untuk menebak apa yang dilakukannya.if(getErrorCode().equals(4095)) ...
Jawaban:
Dalam contoh itu, 1 sangat bermakna.
Namun, bagaimana jika orang. Ukuran () adalah nol? Tampaknya aneh yang
persons.getMoney()
berfungsi untuk 0 dan 2 tetapi tidak untuk 1.sumber
Mengapa sepotong kode mengandung nilai literal tertentu?
Jika nilai literal memiliki makna yang tidak jelas dari konteks, maka ya, memberikan nilai itu nama melalui konstanta atau variabel sangat membantu. Kemudian, ketika konteks asli dilupakan, kode dengan nama variabel yang bermakna akan lebih dapat dipertahankan. Ingat, audiens untuk kode Anda bukan terutama kompiler (kompiler dengan senang hati akan bekerja dengan kode yang mengerikan), tetapi pemelihara kode yang akan datang - yang akan menghargai jika kode tersebut agak menjelaskannya sendiri.
Dalam contoh pertama Anda, makna literal seperti
34
,4
,5
tidak jelas dari konteks. Sebagai gantinya, beberapa nilai ini memiliki makna khusus di domain masalah Anda. Karena itu bagus untuk memberi mereka nama.Dalam contoh kedua Anda, makna literal
1
sangat jelas dari konteksnya. Memperkenalkan nama tidak membantu.Bahkan, memperkenalkan nama untuk nilai yang jelas juga bisa buruk karena menyembunyikan nilai sebenarnya.
Ini dapat mengaburkan bug jika nilai yang disebutkan diubah atau salah, terutama jika variabel yang sama digunakan kembali dalam potongan kode yang tidak terkait.
Sepotong kode mungkin juga berfungsi dengan baik untuk nilai tertentu, tetapi mungkin salah dalam kasus umum. Dengan memperkenalkan abstraksi yang tidak perlu, kodenya tidak lagi benar.
Tidak ada batasan ukuran pada literal "jelas" karena ini sepenuhnya tergantung pada konteks. Misalnya literal
1024
mungkin benar-benar jelas dalam konteks perhitungan ukuran file, atau literal31
dalam konteks fungsi hash, atau literalpadding: 0.5em
dalam konteks CSS stylesheet.sumber
Ada beberapa masalah dengan kode ini, yang, dapat, disingkat menjadi seperti ini:
Tidak jelas mengapa satu orang adalah kasus khusus. Saya kira ada aturan bisnis tertentu yang mengatakan bahwa mendapatkan uang dari satu orang secara radikal berbeda dari mendapatkan uang dari beberapa orang. Namun, saya harus pergi dan melihat ke dalam keduanya
getMoneyIfHasOnePerson
dangetMoney
, berharap untuk memahami mengapa ada kasus yang berbeda.Nama
getMoneyIfHasOnePerson
itu kelihatannya tidak benar. Dari namanya, saya akan mengharapkan metode untuk memeriksa apakah ada satu orang dan, jika ini masalahnya, dapatkan uang darinya; jika tidak, jangan lakukan apa pun. Dari kode Anda, ini bukan yang terjadi (atau Anda melakukan kondisinya dua kali).Apakah ada alasan untuk mengembalikan
List<Money>
koleksi daripada koleksi?Kembali ke pertanyaan Anda, karena tidak jelas mengapa ada perlakuan khusus untuk satu orang, digit yang satu harus diganti dengan konstanta, kecuali ada cara lain untuk membuat aturan eksplisit. Di sini, satu tidak jauh berbeda dari angka ajaib lainnya. Anda dapat memiliki aturan bisnis yang mengatakan bahwa perlakuan khusus berlaku untuk satu, dua atau tiga orang, atau hanya untuk lebih dari dua belas orang.
Anda melakukan apa pun yang membuat kode Anda lebih eksplisit.
Contoh 1
Bayangkan potongan kode berikut:
Apakah nol di sini nilai magis? Kode agak jelas: jika tidak ada elemen dalam urutan, jangan diproses dan mengembalikan nilai khusus. Tetapi kode ini juga dapat ditulis ulang seperti ini:
Di sini, tidak ada lagi yang konstan, dan kodenya bahkan lebih jelas.
Contoh 2
Ambil satu lagi kode:
Tidak perlu terlalu banyak waktu untuk memahami apa yang dilakukannya dalam bahasa seperti JavaScript yang tidak memiliki
round(value, precision)
kelebihan.Sekarang, jika Anda ingin memperkenalkan sebuah konstanta, bagaimana ini akan disebut? Istilah terdekat yang bisa Anda dapatkan adalah
Precision
. Begitu:Apakah ini meningkatkan keterbacaan? Mungkin. Di sini, nilai konstanta agak terbatas, dan Anda mungkin bertanya pada diri sendiri apakah Anda benar-benar perlu melakukan refactoring. Yang menyenangkan di sini adalah bahwa sekarang, ketepatannya dinyatakan hanya sekali, jadi jika itu berubah, Anda tidak mengambil risiko membuat kesalahan seperti:
mengubah nilai di satu lokasi, dan lupa melakukannya di yang lain.
Contoh 3
Dari contoh-contoh itu, Anda mungkin memiliki kesan bahwa angka harus diganti dengan konstanta dalam setiap kasus . Ini tidak benar. Dalam beberapa situasi, memiliki konstanta tidak mengarah pada peningkatan kode.
Ambil bagian kode berikut:
Jika Anda mencoba mengganti nol dengan variabel, kesulitannya adalah menemukan nama yang bermakna. Bagaimana Anda menyebutkannya?
ZeroPosition
?Base
?Default
? Memperkenalkan konstanta di sini tidak akan meningkatkan kode dengan cara apa pun. Itu akan membuatnya sedikit lebih lama, dan hanya itu.Namun kasus seperti itu jarang terjadi. Jadi, setiap kali Anda menemukan angka dalam kode, berusahalah untuk menemukan bagaimana kode tersebut dapat di-refactored. Tanyakan pada diri Anda apakah ada bisnis yang berarti nomor tersebut. Jika ya, konstanta adalah wajib. Jika tidak, bagaimana Anda menyebutkan nomornya? Jika Anda menemukan nama yang bermakna, itu bagus. Jika tidak, kemungkinan Anda menemukan kasus di mana konstanta tidak diperlukan.
sumber
Anda bisa membuat fungsi yang mengambil parameter tunggal dan mengembalikan kali empat dibagi dengan lima yang menawarkan alias bersih ke apa yang dilakukannya saat masih menggunakan contoh pertama.
Saya hanya menawarkan strategi saya sendiri yang biasa tapi mungkin saya akan belajar sesuatu juga.
Apa yang saya pikirkan adalah.
Maaf jika saya salah tetapi saya hanya pengembang javascript. Saya tidak yakin komposisi apa yang saya benarkan ini, saya kira tidak semua harus dalam array atau daftar tetapi. Panjang akan membuat banyak akal. Dan * 4 akan membuat konstanta yang baik karena asalnya tidak jelas.
sumber
Nomor 1 itu, mungkinkah itu nomor yang berbeda? Mungkinkah 2, atau 3, atau adakah alasan logis mengapa harus 1? Jika harus 1, maka menggunakan 1 baik-baik saja. Jika tidak, Anda dapat menentukan konstanta. Jangan sebut SATU konstan itu. (Saya telah melihat itu dilakukan).
60 detik dalam satu menit - apakah Anda memerlukan konstanta? Yah, itu adalah 60 detik, tidak 50 atau 70. Dan semua orang tahu itu. Sehingga bisa tetap nomor.
60 item dicetak per halaman - angka itu bisa dengan mudah menjadi 59 atau 55 atau 70. Sebenarnya, jika Anda mengubah ukuran font, itu mungkin menjadi 55 atau 70. Jadi di sini konstanta yang bermakna lebih ditanyakan.
Ini juga masalah seberapa jelas maknanya. Jika Anda menulis "menit = detik / 60", itu jelas. Jika Anda menulis "x = y / 60", itu tidak jelas. Pasti ada beberapa nama yang bermakna di suatu tempat.
Ada satu aturan absolut: Tidak ada aturan absolut. Dengan latihan Anda akan mengetahui kapan harus menggunakan angka, dan kapan harus menggunakan konstanta bernama. Jangan lakukan itu karena sebuah buku mengatakannya - sampai Anda mengerti mengapa dikatakan demikian.
sumber
minutes*60
, kadang-kadang bahkanhours*3600
ketika saya membutuhkannya tanpa mendeklarasikan konstanta tambahan. Selama berhari-hari saya mungkin menulisd*24*3600
ataud*24*60*60
karena86400
dekat dengan tepi di mana seseorang tidak akan mengenali nomor ajaib itu sekilas.Saya telah melihat cukup banyak kode seperti dalam OP (dimodifikasi) dalam pengambilan DB. Kueri mengembalikan daftar, tetapi aturan bisnis mengatakan hanya ada satu elemen. Dan kemudian, tentu saja, sesuatu berubah untuk 'hanya satu kasus ini' ke daftar dengan lebih dari satu item. (Ya, saya mengatakan cukup banyak kali. Ini hampir seperti mereka ... nm)
Jadi daripada membuat konstanta, saya akan (dalam metode kode bersih) membuat metode untuk memberi nama atau memperjelas apa yang dimaksudkan untuk dideteksi oleh kondisional (dan merangkum bagaimana ia mendeteksi itu):
sumber