Apakah pernah ada ide bagus untuk nilai hardcode ke dalam aplikasi kita? Atau apakah selalu merupakan hal yang tepat untuk memanggil tipe-tipe nilai ini secara dinamis jika mereka perlu berubah?
pi
mungkin berubah ...
Apakah pernah ada ide bagus untuk nilai hardcode ke dalam aplikasi kita? Atau apakah selalu merupakan hal yang tepat untuk memanggil tipe-tipe nilai ini secara dinamis jika mereka perlu berubah?
pi
mungkin berubah ...
Jawaban:
Ya, tetapi jelaskan .
Melakukan:
Jangan:
diameter = 2 * radius
atau diameter = RADIUS_TO_DIAMETER_FACTOR * radius
? Memang ada kasus sudut di mana angka ajaib mungkin solusi yang lebih baik.
diameter = radius << 1
? Saya kira itu juga bisa diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
.
diameter = radius.toDiameter()
Apa yang saya temukan aneh tentang T&J ini sejauh ini adalah bahwa tidak ada yang benar-benar berusaha untuk mendefinisikan dengan jelas "hard-code" atau, yang lebih penting, alternatif.
tl; dr: Ya, itu adalah kadang-kadang ide yang baik untuk nilai hard-code, tetapi tidak ada aturan sederhana untuk saat ; itu tergantung sepenuhnya pada konteks.
Pertanyaannya memang mempersempitnya menjadi nilai - nilai , yang saya maksud dengan angka ajaib , tetapi jawaban untuk apakah itu ide yang baik adalah relatif terhadap apa yang sebenarnya mereka gunakan!
Beberapa contoh nilai "hard-coded" adalah:
Nilai konfigurasi
Saya merasa ngeri setiap kali saya melihat pernyataan seperti command.Timeout = 600
. Kenapa 600? Siapa yang memutuskan itu? Apakah ini waktu sebelumnya, dan seseorang menaikkan batas waktu sebagai peretasan alih-alih memperbaiki masalah kinerja yang mendasarinya? Atau itu sebenarnya harapan yang diketahui dan didokumentasikan untuk waktu pemrosesan?
Ini tidak boleh angka ajaib atau konstanta, mereka harus dieksternalisasi dalam file konfigurasi atau database di suatu tempat dengan nama yang bermakna, karena nilai optimalnya ditentukan sebagian besar atau seluruhnya oleh lingkungan di mana aplikasi berjalan.
Rumus matematika
Rumus biasanya cenderung sangat statis, sehingga sifat dari nilai-nilai konstan di dalamnya tidak terlalu penting. Volume piramida adalah (1/3) b * h. Apakah kita peduli dari mana 1 atau 3 berasal? Tidak juga. Seorang komentator sebelumnya dengan tepat menunjukkan bahwa diameter = radius * 2
mungkin lebih baik daripada diameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR
- tetapi itu adalah dikotomi yang salah.
Apa yang harus Anda lakukan untuk jenis skenario ini adalah membuat fungsi . Saya tidak perlu tahu bagaimana Anda membuat formula tetapi saya masih perlu tahu untuk apa itu . Jika, alih-alih omong kosong yang ditulis di atas, saya menulis volume = GetVolumeOfPyramid(base, height)
kemudian tiba-tiba semuanya menjadi jauh lebih jelas, dan tidak apa-apa memiliki angka ajaib di dalam fungsi ( return base * height / 3
) karena jelas bahwa mereka hanya bagian dari rumus.
Kuncinya di sini tentu saja memiliki fungsi pendek dan sederhana . Ini tidak berfungsi untuk fungsi dengan 10 argumen dan 30 baris perhitungan. Gunakan komposisi fungsi atau konstanta dalam kasus itu.
Aturan domain / bisnis
Yang ini selalu area abu-abu karena tergantung pada apa tepatnya nilainya. Sebagian besar waktu, angka ajaib inilah yang merupakan kandidat untuk berubah menjadi konstanta, karena itu membuat program lebih mudah dipahami tanpa menyulitkan logika program. Pertimbangkan tes if Age < 19
vs if Age < LegalDrinkingAge
; Anda mungkin dapat mengetahui apa yang terjadi tanpa konstanta, tetapi lebih mudah dengan judul deskriptif.
Ini juga dapat menjadi kandidat untuk abstraksi fungsi, misalnya function isLegalDrinkingAge(age) { return age >= 19 }
. Satu-satunya hal adalah bahwa seringkali logika bisnis Anda jauh lebih berbelit-belit daripada itu, dan mungkin tidak masuk akal untuk mulai menulis lusinan fungsi dengan masing-masing 20-30 parameter. Jika tidak ada abstraksi yang jelas berdasarkan objek dan / atau fungsi maka beralih ke konstanta adalah OK.
Peringatannya adalah, jika Anda bekerja untuk departemen pajak, menjadi sangat, sangat membebani dan jujur tidak ada gunanya menulis AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR)
. Anda tidak akan melakukan itu, Anda akan melakukannya AttachForm("B-46")
karena setiap pengembang tunggal yang pernah bekerja atau pernah akan bekerja di sana akan tahu bahwa "B-46" adalah kode formulir untuk wajib pajak tunggal yang mengajukan bla bla bla - kode formulir adalah bagian dari domain itu sendiri, mereka tidak pernah berubah, jadi itu bukan angka ajaib.
Jadi, Anda harus menggunakan konstanta hemat dalam logika bisnis; pada dasarnya Anda harus memahami apakah "angka ajaib" itu sebenarnya angka ajaib atau apakah itu aspek domain yang terkenal. Jika itu domain, maka Anda tidak melakukan soft-code kecuali ada peluang yang benar-benar bagus untuk berubah.
Kode kesalahan dan bendera status
Ini tidak pernah oke untuk hard-code, seperti bajingan miskin yang pernah dipukul dengan Previous action failed due to error code 46
dapat memberitahu Anda. Jika bahasa Anda mendukungnya, Anda harus menggunakan jenis enumerasi. Jika tidak, Anda biasanya memiliki seluruh file / modul penuh konstanta yang menentukan nilai yang valid untuk jenis kesalahan tertentu.
Jangan pernah biarkan saya melihat return 42
penangan kesalahan, capiche? Tidak ada alasan.
Saya mungkin meninggalkan beberapa skenario tetapi saya pikir itu mencakup sebagian besar dari mereka.
Jadi, ya, kadang-kadang praktik yang diterima untuk hal-hal kode sulit. Hanya saja, jangan malas tentang itu; itu harus menjadi keputusan sadar daripada kode ceroboh tua yang biasa.
Ada berbagai alasan untuk menetapkan pengidentifikasi ke nomor.
Ini memberi kita kriteria untuk literal hard-coding. Mereka harus tidak berubah, tidak sulit untuk mengetik, terjadi di satu tempat atau konteks saja, dan dengan makna yang dapat dikenali. Tidak ada gunanya mendefinisikan 0 sebagai ARRAY_BEGINNING, misalnya, atau 1 sebagai ARRAY_INCREMENT.
Sebagai tambahan jawaban lainnya. Gunakan konstanta untuk string bila memungkinkan. Tentu saja, Anda tidak mau memilikinya
const string server_var="server_var";
tetapi Anda harus melakukannya
const string MySelectQuery="select * from mytable;";
(dengan asumsi Anda benar-benar memiliki kueri di mana Anda ingin mendapatkan semua hasil dari tabel tertentu, selalu)
Selain itu, gunakan konstanta untuk angka selain 0 (biasanya). Jika Anda memerlukan bitmask izin 255, jangan gunakan
const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.
alih-alih gunakan
const int AllowGlobalRead=255;
Tentu saja, bersama dengan konstanta, tahu kapan harus menggunakan enumerator. Kasing di atas mungkin akan cocok dalam satu.
typedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
Itu tergantung apa yang Anda anggap sebagai hardcoding. Jika Anda mencoba menghindari setiap dan semua hal yang dikodekan dengan keras , Anda berakhir di wilayah softcoding , dan membuat sistem yang hanya bisa dikelola oleh pembuatnya (dan itulah hardcode utama)
Banyak hal yang dikodekan dalam kerangka kerja yang masuk akal dan mereka bekerja. yaitu tidak ada alasan teknis mengapa saya tidak dapat mengubah titik masuk aplikasi C # (static void Main), tetapi hardcoding yang tidak menimbulkan masalah bagi pengguna mana pun (kecuali sesekali pertanyaan SO )
Aturan praktis yang saya gunakan adalah bahwa segala sesuatu yang dapat dan akan berubah, tanpa mempengaruhi keadaan keseluruhan sistem, harus dapat dikonfirmasikan.
Jadi, IMHO, konyol untuk tidak melakukan hardcode hal-hal yang tidak pernah berubah (pi, konstanta gravitasi, konstanta dalam rumus matematika - pikirkan volume bola).
Juga konyol untuk tidak melakukan hardcode pada hal-hal atau proses yang akan berdampak pada sistem Anda yang akan memerlukan pemrograman dalam hal apa pun, yaitu pemborosan untuk memperbolehkan pengguna untuk menambahkan bidang dinamis ke formulir, jika bidang tambahan apa pun membutuhkan pengembang pemeliharaan untuk masuk dan tulis beberapa skrip yang akan membuat hal itu bekerja. Juga itu bodoh (dan saya sudah melihatnya beberapa kali di lingkungan perusahaan) untuk membuat beberapa alat konfigurasi, jadi tidak ada yang di-hardcode, namun, hanya pengembang di departemen IT yang dapat menggunakannya, dan hanya sedikit lebih mudah untuk menggunakannya daripada untuk melakukannya di Visual Studio.
Jadi, intinya, apakah suatu hal harus hardcoded adalah fungsi dari dua variabel:
Apakah pernah ada ide bagus untuk nilai hardcode ke dalam aplikasi kita?
Saya nilai-nilai hardcode hanya jika nilai-nilai yang ditentukan dalam Spesifikasi (pada rilis akhir spesifikasi), mis. Respons HTTP OK akan selalu 200
(kecuali jika berubah dalam RFC), jadi, Anda akan melihat (dalam beberapa kode saya ) konstanta seperti:
public static final int HTTP_OK = 200;
Kalau tidak, saya menyimpan konstanta dalam file properti.
Alasan mengapa saya menentukan spesifikasi, adalah bahwa perubahan konstanta dalam spesifikasi memerlukan manajemen perubahan, di mana, para pemangku kepentingan akan meninjau perubahan dan menyetujui / menolak. Itu tidak pernah terjadi dalam semalam dan butuh berbulan-bulan / tahun untuk persetujuan. Jangan lupa bahwa banyak pengembang menggunakan spesifikasi (misalnya HTTP) sehingga mengubahnya berarti melanggar jutaan sistem.
Saya perhatikan bahwa setiap kali Anda dapat mengekstrak data dari kode Anda, itu meningkatkan apa yang tersisa. Anda mulai memperhatikan refactor baru dan meningkatkan seluruh bagian kode Anda.
Itu hanya ide yang baik untuk bekerja mengekstraksi konstanta, jangan menganggapnya sebagai aturan bodoh, pikirkan itu sebagai kesempatan untuk kode yang lebih baik.
Keuntungan terbesar adalah cara Anda dapat menemukan konstanta yang sama menjadi satu-satunya perbedaan dalam kelompok kode - mengabstraksi mereka menjadi array telah membantu saya mengurangi beberapa file hingga 90% dari ukurannya dan memperbaiki beberapa bug copy & paste sementara itu .
Saya belum melihat satu keuntungan untuk tidak mengekstraksi data.
Baru-baru ini saya membuat kode fungsi MySQL untuk menghitung jarak antara dua pasangan lat / panjang dengan benar. Anda tidak bisa hanya melakukan pythagorus; garis bujur semakin dekat seiring dengan meningkatnya lintang ke arah kutub, jadi ada beberapa trigonometri berbulu yang terlibat. Intinya adalah, saya cukup terpecah tentang apakah kode-keras nilai mewakili jari-jari bumi dalam mil.
Saya akhirnya melakukannya, meskipun kenyataannya adalah, garis lat / lng lebih dekat bersama, katakanlah, bulan. Dan fungsi saya akan secara drastis melaporkan jarak antara titik-titik di Jupiter. Saya pikir peluang situs web yang saya bangun memiliki lokasi luar angkasa yang masuk cukup kecil.
Yah itu tergantung jika bahasa Anda dikompilasi. Jika tidak dikompilasi, itu bukan masalah besar, Anda cukup mengedit kode sumber, bahkan jika itu akan sedikit rumit untuk non programmer.
Jika Anda memprogram dengan bahasa yang dikompilasi, ini jelas bukan ide yang baik, karena jika variabel berubah, Anda harus mengkompilasi ulang, yang merupakan pemborosan waktu jika Anda ingin menyesuaikan variabel ini.
Anda tidak perlu membuat slider atau antarmuka untuk mengubah variabelnya secara dinamis, tetapi yang paling bisa Anda lakukan adalah file teks.
Sebagai contoh dengan proyek raksasa saya, saya selalu menggunakan kelas ConfigFile untuk memuat variabel yang saya tulis ke file konfigurasi.
Dua kesempatan di mana konstanta (menurut saya setidaknya) OK:
Konstanta yang tidak berhubungan dengan hal lain; Anda dapat mengubah konstanta tersebut kapan pun Anda suka tanpa harus mengubah apa pun. Contoh: Lebar default kolom kisi.
Konstanta yang benar-benar abadi, tepat, dan jelas, seperti "jumlah hari per minggu". days = weeks * 7
Mengganti 7
dengan konstanta DAYS_PER_WEEK
hampir tidak memberikan nilai apa pun.
Saya setuju sepenuhnya dengan Jonathan tetapi karena semua aturan ada pengecualian ...
"Nomor ajaib dalam spec: Nomor ajaib dalam kode"
Pada dasarnya menyatakan bahwa setiap angka ajaib yang tetap dalam spesifikasi setelah upaya yang masuk akal untuk mendapatkan konteks deskriptif untuk mereka harus tercermin dalam kode. Jika angka ajaib tetap ada dalam kode, setiap upaya harus dilakukan untuk mengisolasi mereka dan membuatnya jelas terkait dengan titik asal mereka.
Saya telah melakukan beberapa kontrak interfacing di mana perlu mengisi pesan dengan nilai-nilai yang dipetakan dari database. Dalam kebanyakan kasus, pemetaannya cukup lurus ke depan dan cocok dengan garis panduan umum Jonathan, tetapi saya telah menemukan kasus di mana struktur pesan target sangat buruk. Lebih dari 80% nilai yang harus diwariskan dalam struktur adalah konstanta yang ditegakkan oleh spesifikasi sistem yang jauh. ini ditambah dengan fakta bahwa struktur pesan itu raksasa sehingga BANYAK konstanta seperti itu harus diisi. Dalam kebanyakan kasus mereka tidak memberikan arti atau alasan, hanya mengatakan "taruh M di sini" atau "taruh 4.10.53.10100.889450.4452 di sini". Saya tidak mencoba untuk memberikan komentar di sebelah mereka semua itu akan membuat kode yang dihasilkan tidak dapat dibaca.
Yang mengatakan, ketika Anda memikirkannya ... itu hampir semua tentang membuatnya jelas ...
Jika Anda melakukan hardcoding nilai konstanta gravitasi bumi, tidak ada yang akan peduli. Jika Anda meng-hardcode alamat IP server proxy Anda, berarti Anda dalam masalah.
Kebanyakan tidak, tapi saya pikir patut dicatat bahwa Anda akan memiliki masalah paling banyak ketika Anda mulai menduplikasi nilai hard-coded. Jika Anda tidak menduplikasi (mis. Menggunakannya hanya sekali dalam implementasi kelas) maka tidak menggunakan konstanta mungkin baik-baik saja.