Penggunaan string / angka ajaib [tertutup]

31

Ini adalah topik yang agak kontroversial, dan saya kira ada banyak pendapat karena ada programmer. Tetapi demi itu, saya ingin tahu apa praktik umum dalam bisnis (atau di tempat kerja Anda).

Di tempat kerja saya, kami memiliki pedoman pengkodean yang ketat. Satu bagian dari itu didedikasikan untuk string / angka ajaib. Ini menyatakan (untuk C #):

Jangan gunakan nilai literal, baik numerik atau string, dalam kode Anda selain untuk mendefinisikan konstanta simbolik. Gunakan pola berikut untuk mendefinisikan konstanta:

public class Whatever  
{  
   public static readonly Color PapayaWhip = new Color(0xFFEFD5);  
   public const int MaxNumberOfWheels = 18;  
}

Ada pengecualian: nilai 0, 1 dan nol hampir selalu dapat digunakan dengan aman. Sangat sering nilai 2 dan -1 juga OK. String yang dimaksudkan untuk logging atau tracing dikecualikan dari aturan ini. Literal diizinkan ketika maknanya jelas dari konteksnya, dan tidak tunduk pada perubahan di masa depan.

mean = (a + b) / 2; // okay  
WaitMilliseconds(waitTimeInSeconds * 1000); // clear enough

Situasi yang ideal adalah beberapa makalah penelitian resmi yang menunjukkan efek pada keterbacaan / pemeliharaan kode ketika:

  • Angka ajaib / senar ada di semua tempat
  • String / angka ajaib digantikan oleh deklarasi konstan secara wajar (atau dalam berbagai tingkat cakupan) - dan tolong jangan meneriaki saya karena menggunakan "cukup", saya tahu semua orang memiliki ide yang berbeda apa "cukup" itu
  • String / angka ajaib ditempatkan secara berlebihan dan di tempat-tempat di mana mereka tidak harus (lihat contoh saya di bawah)

Saya ingin melakukan ini untuk memiliki beberapa argumen berbasis ilmiah ketika berdebat dengan salah satu kolega saya, yang akan sampai pada titik menyatakan konstanta seperti:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Contoh lain adalah (dan ini dalam JavaScript):

var someNumericDisplay = new NumericDisplay("#Div_ID_Here");

Apakah Anda menempelkan DOM ID di atas file javascript Anda jika ID itu hanya digunakan di 1 tempat?

Saya telah membaca topik-topik berikut:
StackExchange
StackOverflow
Bytes Komunitas TI
Ada banyak lagi artikel, dan setelah membaca beberapa pola ini muncul.

Jadi pertanyaan saya adalah harus menggunakan string dan angka ajaib dalam kode kita? Saya secara khusus mencari jawaban ahli yang didukung oleh referensi jika memungkinkan.

Daniel Gruszczyk
sumber
2
Variabel ajaib adalah variabel yang menyimpan makna yang tidak tercermin oleh isinya. Nilai integer '10' mencerminkan arti angka 10, jadi tidak perlu membuatnya konstan. Hal yang sama berlaku untuk ruang dan titik koma. Di sisi lain, jika Anda memiliki nilai '%% ?? %%' dan ini adalah pembatas khusus, maka HAS harus ditempatkan sebagai konstanta karena isinya tidak mencerminkan fakta bahwa itu adalah pembatas.
Jeroen Vannevel
23
NumberTen = 10Itu tidak ada gunanya karena angka 10 tidak akan didefinisikan ulang. MaxRetryCount = 10Itu ada titik a kita mungkin ingin mengubah jumlah coba lagi maks. private const char SemiColon = ';'; Bodoh. private const char LineTerminator = ';'; Pintar.
Mike
1
Pertanyaan aktual tidak jelas.
Tulains Córdova

Jawaban:

89

... ketika berdebat dengan salah satu kolega saya, yang akan langsung menyatakan konstanta seperti:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Argumen yang perlu Anda ajukan dengan kolega Anda bukan tentang penamaan ruang literal Spacemelainkan pilihan nama yang buruk untuk konstanta-konstanta.

Katakanlah tugas kode Anda adalah mengurai aliran catatan yang berisi bidang yang dipisahkan oleh tanda titik koma ( a;b;c) dan dipisahkan oleh spasi ( a;b;c d;e;f). Jika siapa pun yang menulis spec Anda memanggil Anda sebulan dari sekarang dan berkata, "kami salah, bidang dalam catatan dipisahkan oleh simbol pipa ( a|b|c d|e|f)," apa yang Anda lakukan?

Di bawah skema nilai-sebagai-nama yang disukai kolega Anda, Anda harus mengubah nilai literal ( SemiColon = '|') dan hidup dengan kode yang terus digunakan SemiColonuntuk sesuatu yang tidak benar-benar titik koma lagi. Itu akan menghasilkan komentar negatif dalam ulasan kode . Untuk menguranginya, Anda dapat mengubah nama literal menjadi PipeSymboldan melewati dan mengubah setiap kemunculan SemiColonke PipeSymbol. Pada tingkat itu Anda mungkin baru saja menggunakan titik koma literal ( ';'), karena Anda harus mengevaluasi setiap penggunaannya secara individual dan Anda akan membuat jumlah perubahan yang sama.

Pengidentifikasi untuk konstanta harus deskriptif apa nilai tidak , tidak apa nilai adalah , dan bahwa di mana rekan Anda telah membuat berbelok ke kiri ke dalam gulma. Dalam aplikasi pemisahan lapangan yang dijelaskan di atas, tujuan titik koma adalah pemisah medan, dan konstanta harus dinamai sesuai:

private const char FieldSeparator = ';';    // Will become '|' a month from now
private const char RecordSeparator = ' ';
private const int MaxFieldsPerRecord = 10;

Dengan cara ini, ketika pemisah bidang berubah, Anda mengubah tepat satu baris kode, pernyataan konstanta. Seseorang yang melihat perubahan akan melihat hanya satu baris itu dan akan segera memahami bahwa pemisah bidang berubah dari tanda titik koma menjadi simbol pipa. Sisa kode, yang tidak perlu diubah karena menggunakan konstanta, tetap sama, dan pembaca tidak perlu menggali untuk melihat apa yang dilakukan untuk itu.

Blrfl
sumber
Saya sangat setuju. Beberapa dekade yang lalu saya mengerjakan proyek di mana pesan dikirim dalam segmen, masing-masing menggunakan 8 register umum. Seseorang telah mendeklarasikan #define one 1 #define two 2 dll (atau apa pun yang sederajat itu di UK Post Office Coral, bahasa pilihan saat itu). Kata datang dari atas bahwa di masa depan bidang panjang akan menjadi jumlah byte, bukan segmen, jadi jelas kode itu diubah menjadi #define one 8 #define two 16 dll
Mawg
3
Konyol seperti nama-nama seperti Titik koma atau PipeSymbol tampaknya, mengubah satu ke yang lain menggunakan script akan jauh lebih mudah daripada mengubah setiap terpengaruh ;untuk |.
Brandin
Bagaimana dengan kasus di mana String literal yang diberikan digunakan berkali-kali dalam file, tetapi tidak memiliki arti selain nilainya? Misalnya, jika Anda menguji bahwa Anda dapat menerima kunci tertentu di peta dalam 20 skenario perbedaan, haruskah saya mendefinisikan konstanta seperti itu ?: public static final String MY_KEY_NAME = "MyKeyName"
Jordan McQueen
1
@JordanMcQueen Ada kasus yang harus dibuat untuk menggunakan bare literal jika (dan hanya jika) masing-masing digunakan tepat sekali dan tidak diperlukan di tempat lain. Jika sesuatu itu seperti setiap skenario kode makhluk yang proses format file yang berbeda, masing-masing format harus mendefinisikan konstan sendiri (misalnya, CSV_RECORD_SEPARATOR, TSV_RECORD_SEPARATOR, dll).
Blrfl
8

Mendefinisikan titik koma sebagai konstanta adalah mubazir, karena titik koma sudah konstan dengan sendirinya . Itu tidak akan pernah berubah.

Ini tidak seperti suatu hari seseorang akan mengumumkan "perubahan terminologi, + adalah titik koma baru sekarang", dan kolega Anda akan dengan senang hati bergegas hanya untuk memperbarui konstanta (mereka menertawakan saya - lihat mereka sekarang).

Ada juga masalah konsistensi. Saya menjamin bahwa NumberTenkonstanta nya TIDAK akan digunakan oleh semua orang (kebanyakan coders tidak keluar dari pikiran mereka), jadi itu tidak akan melayani tujuan apa pun yang diharapkan pula. Ketika kiamat datang dan "sepuluh" akan secara global diubah menjadi 9, memperbarui konstanta TIDAK akan melakukan trik, karena itu masih akan meninggalkan Anda dengan tumpukan literal 10dalam kode Anda, jadi sekarang sistem menjadi benar-benar tidak dapat diprediksi bahkan dalam ruang lingkup dari asumsi revolusioner bahwa "sepuluh" berarti "9".

Menyimpan semua pengaturan sebagai const adalah sesuatu yang saya juga pikirkan. Seseorang seharusnya tidak melakukan ini dengan enteng.

Apa contoh penggunaan seperti ini yang telah kami kumpulkan sejauh ini? Terminator garis ... jumlah coba lagi maks ... jumlah roda maksimum ... apakah kami yakin ini tidak akan pernah berubah?

Biayanya adalah bahwa mengubah pengaturan default memerlukan kompilasi ulang aplikasi, dan dalam beberapa kasus, bahkan dependensinya (karena nilai konstanta numerik mungkin mendapatkan kode-keras selama kompilasi).

Ada juga aspek pengujian dan mengejek. Anda mendefinisikan string koneksi sebagai const, tetapi sekarang oops Anda tidak dapat mengejek akses database (membuat koneksi palsu) di unit test Anda.

Konrad Morawski
sumber
4
"Itu tidak akan pernah berubah." Dulu saya berpikir tentang apostrof (selamanya terikat dengan nilai ASCII 39). Beberapa aplikasi lama digunakan untuk menggulung apostrof. Tetapi sekarang aplikasi modern memperlakukan nilai ASCII sebagai tanda kutip lurus yang kompatibel dengan aplikasi lama, dan sebagai gantinya orang sering menggunakan (kutipan tunggal, Unicode 8217 ) untuk aplikasi yang kompatibel dengan menampilkan mesin terbang yang berbeda untuk tanda keriting. Menjadi bahwa Eropa menggunakan koma cara Amerika menggunakan titik sebagai titik desimal, saya menemukan diri saya sedikit ragu untuk menyatakan "tidak ... pernah".
TOOGAM
@TOOGAM, contoh Anda membenarkan memiliki DecimalPointkonstanta - tetapi tidak Commaatau Periodkonstanta. Perbedaannya cukup besar: yang pertama menunjukkan fungsi , peran atau tujuan dari nilai. "Titik koma" atau "koma" tidak termasuk dalam kategori itu.
Konrad Morawski
Itu benar untuk contoh Titik Desimal. Namun, contoh apostrof tampaknya memiliki kategori yang sama (atau identik) dengan koma (atau semi-kolon).
TOOGAM
@KonradMorawski Semicolon dapat digunakan untuk banyak tujuan, seperti membelah string atau mengakhiri garis. Arti dari itu (bukan nilai) yang harus digunakan untuk penamaan constance. Pertimbangkan perubahan di masa depan, yaitu besok kami mengizinkan 20 catatan untuk diproses, jadi constance yang dinamai NumberTen berada di luar konteks, sementara maxRecord masih akan baik-baik saja.
MaxZoom
5
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Jadi kolega Anda membidik entri WTF Harian. Definisi-definisi itu konyol dan berlebihan. Namun, seperti yang telah ditunjukkan oleh orang lain, definisi berikut tidak akan konyol atau berlebihan:

private const char StatementTerminator = ';';
private const char Delimiter = ' ';
private const int  BalanceInquiryCode = 10;

Angka dan senar "ajaib" adalah konstanta yang memiliki makna di luar nilai langsung dan harfiahnya. Jika konstanta 10memiliki makna di luar "sepuluh hal" (katakanlah sebagai kode untuk operasi atau kondisi kesalahan tertentu), saat itulah ia menjadi "ajaib" dan harus diganti dengan konstanta simbolik yang menggambarkan makna abstrak itu.

Di luar jelas menggambarkan niat, konstanta simbolis juga menyelamatkan Anda dari sakit kepala ketika Anda salah mengeja literal. Transposisi sederhana dari "CVS" ke "CSV" dalam satu baris kode berhasil melalui pengujian unit dan QA dan membuatnya menjadi produksi, di mana ia menyebabkan operasi tertentu gagal. Ya, jelas unit dan tes QA tidak lengkap dan itu masalah sendiri, tetapi menggunakan konstanta simbolis akan menghindari sedikit mulas itu sama sekali.

John Bode
sumber
3

Seharusnya tidak ada yang kontroversial tentang hal itu. Intinya bukan tentang apakah menggunakan angka ajaib atau tidak, intinya adalah memiliki kode yang dapat dibaca.
Pertimbangkan perbedaan antara: if(request.StatusCode == 1)dan if(request.HasSucceeded). Dalam hal ini, saya berpendapat bahwa yang terakhir jauh lebih mudah dibaca, tetapi itu tidak berarti Anda tidak akan pernah memiliki kode seperti int MaxNumberOfWheels = 18.

PS: Inilah sebabnya saya sangat membenci pedoman pengkodean. Pengembang harus cukup dewasa untuk dapat membuat penilaian seperti ini; mereka tidak harus menyerahkannya pada selembar teks yang dibentuk oleh dewa yang tahu siapa.

Stefan Billiet
sumber
13
Pengemudi harus cukup matang untuk dapat membuat keputusan di sisi jalan mana yang mereka kendarai;)
Konrad Morawski
2
Hasil dari panggilan penilaian dapat bervariasi bahkan antara pengembang dewasa, sehingga pedoman pengkodean sewenang-wenang pun dimaksudkan untuk meningkatkan keterbacaan melalui konsistensi. Ini tidak terkait dengan fakta bahwa menciptakan NumberTen yang konstan tidak masuk akal.
Mike Partridge
1
Saya tidak akan bersikeras bahwa mereka harus formal, dicap dll, mereka bisa informal tetapi mereka harus disepakati, dan ini sudah melampaui hanya menggunakan kematangan penilaian individu seseorang. Tetapi Anda menghapus komentar Anda sekarang Stefan :)
Konrad Morawski
1
@StefanBilliet - sama sekali tidak. Maksud saya adalah keterbacaan ditingkatkan melalui konsistensi. Masalahnya di sini bukanlah pedoman pengkodean itu sendiri, tetapi pedoman yang diambil secara ekstrem melalui kesalahpahaman.
Mike Partridge
@ MikePartridge Mungkin saya harus menjelaskan; pedoman pengkodean yang saya lihat lebih banyak dalam tren buku aturan umum tentang bagaimana seseorang di suatu tempat berpikir bahwa perangkat lunak harus ditulis, daripada perjanjian seperti Anda dan Konrad yang mungkin pikirkan :-)
Stefan Billiet