Di artikel ini oleh Alex Papadimoulis, Anda dapat melihat cuplikan ini:
private void attachSupplementalDocuments()
{
if (stateCode == "AZ" || stateCode == "TX") {
//SR008-04X/I are always required in these states
attachDocument("SR008-04X");
attachDocument("SR008-04XI");
}
if (ledgerAmnt >= 500000) {
//Ledger of 500K or more requires AUTHLDG-1A
attachDocument("AUTHLDG-1A");
}
if (coInsuredCount >= 5 && orgStatusCode != "CORP") {
//Non-CORP orgs with 5 or more co-ins require AUTHCNS-1A
attachDocument("AUTHCNS-1A");
}
}
Saya benar-benar tidak mengerti artikel ini.
Saya mengutip:
Jika setiap aturan bisnis konstan disimpan dalam beberapa file konfigurasi, hidup akan jauh [lebih ( sic )] sulit bagi semua orang menjaga perangkat lunak: akan ada banyak file kode yang berbagi satu, file besar (atau, sebaliknya, banyak sekali file konfigurasi kecil); menyebarkan perubahan pada aturan bisnis tidak memerlukan kode baru, tetapi secara manual mengubah file konfigurasi; dan debugging jauh lebih sulit.
Ini adalah argumen yang menentang memiliki bilangan bulat konstan "500000" dalam file konfigurasi, atau "AUTHCNS-1A" dan konstanta string lainnya.
Bagaimana ini bisa menjadi praktik yang buruk?
Dalam cuplikan ini, "500000" bukan angka. Misalnya, tidak sama dengan:
int doubleMe(int a) { return a * 2;}
di mana 2, adalah angka yang tidak perlu diabstraksi. Penggunaannya jelas, dan itu tidak mewakili sesuatu yang dapat digunakan kembali nanti.
Sebaliknya, "500000" bukan sekadar angka. Ini nilai yang signifikan, nilai yang mewakili ide breakpoint dalam fungsionalitas. Nomor ini dapat digunakan di lebih dari satu tempat, tetapi bukan nomor yang Anda gunakan; itu adalah gagasan tentang batas / batas, di bawah mana satu aturan berlaku, dan di atasnya yang lain.
Bagaimana merujuknya dari file konfigurasi, atau bahkan #define
, const
atau apa pun yang disediakan bahasa Anda, lebih buruk daripada memasukkan nilainya? Jika nanti pada program, atau programmer lain, juga memerlukan garis batas itu, sehingga perangkat lunak membuat pilihan lain, Anda kacau (karena ketika itu berubah, tidak ada yang menjamin Anda bahwa itu akan berubah di kedua file). Itu jelas lebih buruk untuk debugging.
Selain itu, jika besok, pemerintah menuntut "Dari 5/3/2050, Anda perlu menambahkan AUTHLDG-122B alih-alih AUTHLDG-1A", konstanta string ini bukan konstanta string sederhana. Itu salah satu yang mewakili ide; itu hanya nilai saat ini dari ide itu (yang merupakan "hal yang Anda tambahkan jika buku besar di atas 500k").
Izinkan saya mengklarifikasi. Saya tidak mengatakan bahwa artikel itu salah; Saya tidak mengerti; mungkin itu tidak dijelaskan dengan baik (setidaknya untuk pemikiran saya).
Saya mengerti bahwa mengganti setiap string yang mungkin nilai literal atau numerik dengan variabel konstan, define, atau konfigurasi, tidak hanya tidak perlu, tetapi terlalu rumit, tetapi contoh khusus ini tampaknya tidak termasuk dalam kategori ini. Bagaimana Anda tahu bahwa Anda tidak akan membutuhkannya nanti? Atau orang lain dalam hal ini?
Jawaban:
Penulis memperingatkan abstraksi prematur.
Garis tersebut
if (ledgerAmt > 500000)
terlihat seperti jenis aturan bisnis yang Anda harapkan untuk dilihat untuk sistem bisnis besar yang kompleks yang persyaratannya sangat kompleks namun tepat dan terdokumentasi dengan baik.Biasanya persyaratan semacam itu adalah kasus luar biasa / tepi daripada logika yang dapat digunakan kembali. Persyaratan tersebut biasanya dimiliki dan dikelola oleh analis bisnis dan ahli materi pelajaran, bukan oleh insinyur
(Perhatikan bahwa 'kepemilikan' persyaratan oleh Analis Bisnis / pakar dalam kasus ini biasanya terjadi di mana pengembang yang bekerja di bidang spesialis tidak memiliki keahlian domain yang memadai; meskipun saya masih mengharapkan komunikasi / kerja sama penuh antara pengembang dan pakar domain untuk melindungi dari persyaratan ambigu atau ditulis dengan buruk.)
Ketika memelihara sistem yang persyaratannya dikemas penuh dengan kasus tepi dan logika yang sangat kompleks, biasanya tidak ada cara untuk mengabstraksi logika tersebut atau membuatnya lebih dapat dipertahankan; upaya untuk mencoba membangun abstraksi dapat dengan mudah menjadi bumerang - tidak hanya menghasilkan waktu yang terbuang, tetapi juga menghasilkan kode yang kurang dapat dipelihara.
Jenis kode ini cenderung dijaga oleh fakta bahwa kode itu sendiri mungkin memiliki pemetaan satu-ke-satu dengan persyaratan; yaitu ketika pengembang tahu bahwa
500000
angka tersebut muncul dua kali dalam persyaratan, pengembang itu juga tahu bahwa itu muncul dua kali dalam kode.Pertimbangkan skenario lain (yang kemungkinannya sama) di mana
500000
muncul di banyak tempat dalam dokumen persyaratan, tetapi Ahli Subjek memutuskan untuk hanya mengubah salah satunya; di sana Anda memiliki risiko yang lebih buruk lagi bahwa seseorang yang mengubahconst
nilainya mungkin tidak menyadari bahwa500000
itu digunakan untuk mengartikan hal-hal yang berbeda - sehingga pengembang mengubahnya di satu-satunya tempat ia menemukannya dalam kode, dan akhirnya merusak sesuatu yang mereka tidak menyadari bahwa mereka telah berubah.Skenario ini banyak terjadi pada perangkat lunak hukum / keuangan yang dipesan lebih dahulu (mis. Logika kutipan asuransi) - orang yang menulis dokumen semacam itu bukanlah insinyur, dan mereka tidak memiliki masalah menyalin + menempelkan seluruh bidak dari spesifikasi, memodifikasi beberapa kata / angka, tetapi meninggalkan sebagian besar sama.
Dalam skenario itu, cara terbaik untuk menangani persyaratan salin-tempel adalah dengan menulis kode salin-rekat, dan membuat kode itu terlihat sama dengan persyaratan (termasuk mengode semua data) sebaik mungkin.
Kenyataan dari persyaratan tersebut adalah bahwa mereka biasanya tidak tinggal salin + tempel lama, dan nilai-nilai kadang-kadang berubah secara teratur, tetapi mereka sering tidak berubah bersama-sama, jadi cobalah untuk merasionalisasi atau abstrak persyaratan tersebut keluar atau menyederhanakan mereka dengan cara apa pun akhirnya menciptakan lebih banyak sakit kepala pemeliharaan daripada hanya menerjemahkan persyaratan kata demi kata menjadi kode.
sumber
Those requirements are typically owned and maintained by business analysts and subject matter experts, rather than by engineers
yang tidak selalu merupakan ide yang bagus. Kadang-kadang tindakan mengubah persyaratan tersebut menjadi kode akan mengungkapkan kasus sudut di mana persyaratan tersebut tidak didefinisikan dengan baik atau didefinisikan sedemikian rupa sehingga bertentangan dengan kepentingan bisnis. Jika analis bisnis dan pengembang dapat bekerja sama untuk mencapai tujuan bersama, maka banyak masalah dapat dihindari.Artikel ini memiliki poin bagus. Bagaimana bisa menjadi praktik yang buruk untuk mengekstrak konstanta ke file konfigurasi? Ini bisa menjadi praktik buruk jika menyulitkan kode. Memiliki nilai langsung dalam kode jauh lebih sederhana daripada harus membacanya dari file konfigurasi, dan kode yang ditulis mudah diikuti.
Ya, maka Anda mengubah kode. Maksud artikel ini adalah tidak lebih rumit untuk mengubah kode daripada mengubah file konfigurasi.
Pendekatan yang dijelaskan dalam artikel tidak berskala jika Anda mendapatkan logika yang lebih kompleks, tetapi intinya adalah bahwa Anda harus membuat penilaian, dan kadang-kadang solusi paling sederhana adalah yang terbaik.
Inilah inti dari prinsip YAGNI. Jangan mendesain untuk masa depan yang tidak diketahui yang mungkin berubah sama sekali berbeda, desain untuk saat ini. Anda benar bahwa jika nilai 500000 digunakan beberapa tempat dalam program ini tentu saja harus diekstraksi menjadi konstanta. Tapi ini tidak terjadi dalam kode yang dimaksud.
Softcoding sebenarnya adalah pertanyaan pemisahan masalah . Anda informasi kode lunak yang Anda tahu mungkin berubah secara independen dari logika aplikasi inti. Anda tidak akan pernah mengubah kode string koneksi ke database, karena Anda tahu itu mungkin berubah secara independen dari logika aplikasi dan Anda perlu membedakannya untuk lingkungan yang berbeda. Dalam aplikasi web kami ingin memisahkan logika bisnis dari template html dan style sheet, karena mereka dapat berubah secara independen dan bahkan diubah oleh orang yang berbeda.
Tetapi dalam kasus dalam contoh kode, string dan angka yang di-hardcod merupakan bagian integral dari logika aplikasi. Dapat dibayangkan bahwa satu file dapat mengubah namanya karena beberapa perubahan kebijakan di luar kendali Anda, tetapi dapat dibayangkan bahwa kami perlu menambahkan cabang-baru yang memeriksa kondisi yang berbeda. Mengekstraksi nama dan nomor file benar-benar merusak kohesi dalam kasus ini.
sumber
if
didasarkan pada variabel yang berbeda! Jika variabel yang Anda butuhkan tidak dapat diakses dari konfigurasi, Anda tetap harus memodifikasi perangkat lunak.Artikel selanjutnya membahas tentang 'Enterprise Rule Engine's yang mungkin merupakan contoh yang lebih baik dari apa yang dia bantah.
Logikanya adalah bahwa Anda dapat menggeneralisasi ke titik di mana konfigurasi Anda menjadi sangat rumit sehingga mengandung bahasa pemrograman sendiri.
Misalnya, kode negara untuk mendokumentasikan pemetaan dalam contoh dapat dipindahkan ke file konfigurasi. Tetapi Anda kemudian perlu mengekspresikan hubungan yang kompleks.
Mungkin Anda juga akan memasukkan jumlah buku besar?
Segera Anda menemukan bahwa Anda memprogram dalam bahasa baru yang Anda temukan dan menyimpan kode itu dalam file konfigurasi yang tidak memiliki sumber atau perubahan kontrol.
Perlu dicatat bahwa artikel ini berasal dari 2007 ketika hal semacam ini merupakan pendekatan umum.
Saat ini kami mungkin akan menyelesaikan masalah dengan ketergantungan injeksi (DI). Yaitu, Anda akan memiliki 'kode keras'
yang akan Anda ganti dengan kode keras, atau lebih dapat dikonfigurasi
ketika persyaratan hukum atau bisnis berubah.
sumber
if
pernyataan untuk memberikan nilai yang berbeda untuk setiap klien? Itu terdengar seperti sesuatu yang harus ada dalam file konfigurasi. Berada dalam satu jenis file atau lainnya, semuanya sama, bukan alasan untuk tidak mengontrol / melacak / membuat cadangan file. @ewan tampaknya mengatakan bahwa file DSL tidak dapat disimpan sebagai bagian dari proyek untuk beberapa alasan, bahkan ketika aset non-kode seperti gambar dan file suara dan dokumentasi tentu adalah .Dan itu diungkapkan dengan memiliki (dan saya bisa berpendapat bahwa bahkan komentar itu berlebihan):
Ini hanya mengulangi apa yang dilakukan kode:
Perhatikan bahwa penulis mengasumsikan bahwa arti 500000 terkait dengan aturan ini; itu bukan nilai yang mungkin atau akan digunakan kembali di tempat lain:
Poin utama artikel ini, dalam pandangan saya, adalah bahwa kadang-kadang angka hanyalah angka: itu tidak memiliki arti lain selain apa yang disampaikan dalam kode dan tidak mungkin digunakan di tempat lain. Oleh karena itu, canggung meringkas apa yang dilakukan kode (sekarang) dalam nama variabel hanya demi menghindari nilai-nilai hard-kode adalah pengulangan yang tidak perlu di terbaik.
sumber
LEDGER_AMOUNT_REQUIRING_AUTHLDG1A
, Anda tidak akan menulis komentar ke dalam kode lagi. Komentar tidak dikelola dengan baik oleh programmer. Jika jumlahnya berubah,if
kondisi dan komentar akan keluar dari sinkronisasi. Sebaliknya, konstantaLEDGER_AMOUNT_REQUIRING_AUTHLDG1A
tidak pernah keluar dari sinkronisasi dengan dirinya sendiri dan ia menjelaskan tujuannya tanpa komentar yang tidak perlu.attachDocument("AUTHLDG-2B");
saluran akan gagal memperbarui nama konstan pada saat yang sama. Dalam hal ini, saya pikir kodenya cukup jelas tanpa komentar atau variabel explainer. (Meskipun mungkin masuk akal untuk memiliki konvensi untuk menunjukkan bagian yang sesuai dari dokumen persyaratan bisnis melalui komentar kode. Di bawah konvensi semacam itu, sebuah komentar kode yang melakukan hal itu akan sesuai di sini.)LEDGER_AMOUNT_REQUIRING_ADDITIONAL_DOCUMENTS
(yang mungkin seharusnya saya lakukan di tempat pertama). Saya juga terbiasa memasukkan ID persyaratan bisnis ke dalam pesan commit Git, bukan ke dalam kode sumber.attachIfNecessary()
metode sendiri dan hanya mengulangi semuanya.Jawaban lainnya benar, dan bijaksana. Tapi ini jawaban singkat dan manis saya.
Jika aturan dan nilai khusus muncul di satu tempat dalam kode, dan tidak berubah selama runtime, maka hard-code seperti yang ditunjukkan dalam pertanyaan.
Jika aturan atau nilai khusus muncul di lebih dari satu tempat dalam kode, dan tidak berubah selama runtime, maka kode lunak. Soft-coding untuk suatu aturan mungkin saya mendefinisikan kelas / metode tertentu atau menggunakan pola Builder . Untuk nilai, soft-coding dapat berarti mendefinisikan konstanta tunggal atau enum untuk nilai yang akan digunakan di seluruh kode Anda.
Jika aturan atau nilai khusus dapat berubah selama runtime, maka Anda harus mengeksternalisasi mereka. Ini biasanya dilakukan dengan memperbarui nilai dalam database. Atau perbarui nilai dalam memori secara manual oleh pengguna yang memasukkan data. Hal ini juga dilakukan dengan menyimpan nilai-nilai dalam file teks (XML, JSON, teks biasa, apa pun) yang berulang kali dipindai untuk perubahan tanggal-waktu modifikasi file.
sumber
Ini adalah jebakan yang kita jatuhi ketika kita menggunakan masalah mainan dan kemudian hanya mengajukan solusi stroberi , ketika kita mencoba menggambarkan masalah sebenarnya.
Pada contoh yang diberikan, tidak ada bedanya apakah nilai yang diberikan hardcoded sebagai nilai inline, atau didefinisikan sebagai const.
Ini adalah kode di sekitarnya yang akan membuat contoh pemeliharaan dan pengkodean horor. Jika ada yang tidak ada kode sekitarnya, maka potongan-baik saja, setidaknya di lingkungan refactoring konstan. Dalam lingkungan di mana refactoring cenderung tidak terjadi, pemelihara kode itu sudah mati, karena alasan yang akan segera menjadi jelas.
Lihat, jika ada kode di sekitarnya, maka hal-hal buruk jelas terjadi.
Hal buruk pertama adalah bahwa nilai 50000 digunakan untuk nilai lain di suatu tempat, katakanlah, jumlah buku besar di mana tarif pajak berubah di beberapa negara ... maka ketika perubahan terjadi, pengelola tidak memiliki cara untuk mengetahui, ketika ia menemukan mereka dua contoh kode 50.000, apakah artinya 50k yang sama, atau 50k yang sama sekali tidak terkait. Dan haruskah Anda juga mencari 49999 dan 50001, kalau-kalau ada orang yang menggunakannya juga? Ini bukan panggilan untuk plonk variabel-variabel itu dalam file konfigurasi layanan terpisah: tetapi hardcoding mereka sebaris jelas juga salah. Sebagai gantinya, mereka harus berupa konstanta, didefinisikan dan dicakup dalam kelas atau file di mana mereka digunakan. Jika dua contoh 50k menggunakan konstanta yang sama, maka mereka kemungkinan mewakili pembatasan legislatif yang sama; jika tidak, mereka mungkin tidak; dan bagaimanapun, mereka akan memiliki nama,
Nama file diteruskan ke fungsi - attachDocument () - yang menerima nama file dasar sebagai string, tanpa path atau ekstensi. Nama file pada dasarnya adalah kunci asing ke beberapa sistem file, atau basis data, atau dari mana pun attachDocument () mendapatkan file. Tetapi string tidak memberi tahu Anda tentang hal ini - berapa banyak file yang ada? Apa jenis file mereka? Bagaimana Anda tahu, ketika membuka pasar baru, apakah Anda perlu memperbarui fungsi ini? Ke hal apa mereka bisa dilampirkan? Pemelihara dibiarkan sepenuhnya dalam kegelapan, dan semua yang dimilikinya adalah string, yang dapat muncul beberapa kali dalam kode dan berarti hal yang berbeda setiap kali muncul. Di satu tempat, "SR008-04X" adalah kode cheat. Di lain, itu adalah perintah untuk memesan empat roket pendorong SR008. Ini dia' sa nama file? Apakah ini terkait? Seseorang baru saja mengubah fungsi itu untuk menyebutkan file lain, "CLIENT". Maka Anda, pengelola yang buruk, telah diberi tahu bahwa file "KLIEN" perlu diganti namanya menjadi "PELANGGAN". Tetapi string "CLIENT" muncul 937 kali dalam kode ... di mana Anda bahkan mulai mencari?
Masalah mainannya adalah bahwa semua nilainya tidak biasa dan dapat dijamin secara unik untuk menjadi unik dalam kode. Bukan "1" atau "10" tetapi "50.000". Bukan "klien" atau "laporkan" tetapi "SR008-04X".
The strawman adalah bahwa satu-satunya cara lain untuk mengatasi masalah konstanta impenetrably buram adalah untuk sarang mereka kabur ke file konfigurasi dari beberapa layanan yang tidak terkait.
Bersama-sama, Anda dapat menggunakan dua kesalahan ini untuk membuktikan argumen apa pun yang benar.
sumber
if (...) { attachDocument(...); }
.Ada beberapa masalah dalam hal ini.
Salah satu masalah adalah apakah sebuah mesin aturan harus dibuat untuk membuat semua aturan mudah dikonfigurasi di luar program itu sendiri. Jawaban dalam kasus yang mirip dengan ini paling sering tidak. Aturan akan berubah dengan cara aneh yang sulit diprediksi yang berarti bahwa mesin aturan harus diperpanjang setiap kali ada perubahan.
Masalah lain adalah bagaimana menangani aturan-aturan ini dan perubahannya dalam kontrol versi Anda. Solusi terbaik di sini adalah dengan membagi aturan menjadi kelas untuk setiap aturan.
Yang memungkinkan setiap aturan untuk memiliki validitasnya sendiri, beberapa peraturan berubah setiap tahun, beberapa perubahan tergantung pada kapan izin telah diberikan atau faktur dikeluarkan. Aturan itu sendiri berisi cek versi mana yang harus diterapkan.
Juga karena konstanta bersifat pribadi itu tidak dapat disalahgunakan di tempat lain dalam kode.
Kemudian miliki daftar semua aturan dan terapkan daftar itu.
Masalah selanjutnya adalah bagaimana menangani konstanta. 500000 mungkin terlihat tidak mencolok tetapi harus sangat hati-hati untuk memastikannya dikonversi dengan benar. Jika ada aritmatika floating point diterapkan itu mungkin dikonversi ke 500.000,00001 sehingga perbandingan dengan 500.000,00000 mungkin gagal. Atau 500000 lebih buruk selalu berfungsi seperti yang dimaksudkan, tetapi entah bagaimana 565000 gagal ketika dikonversi. Pastikan konversi itu eksplisit dan dibuat oleh Anda bukan oleh tebak kompiler. Seringkali ini dilakukan dengan mengonversinya ke BigInteger atau BigDecimal sebelum digunakan.
sumber
Meskipun tidak secara langsung disebutkan dalam pertanyaan, saya ingin mencatat bahwa yang penting adalah tidak mengubur logika bisnis dalam kode.
Kode, seperti contoh di atas, yang menyandikan persyaratan bisnis yang ditentukan secara eksternal harus benar-benar hidup di bagian berbeda dari pohon sumber, mungkin dinamai
businesslogic
atau sesuatu yang serupa, dan harus berhati-hati untuk memastikan bahwa itu hanya menyandikan persyaratan bisnis secara sederhana, mudah dibaca dan seringkas mungkin, dengan boilerplate minimum dan dengan komentar yang jelas dan informatif.Seharusnya tidak dicampur dengan kode "infrastruktur" yang mengimplementasikan fungsi yang diperlukan untuk menjalankan logika bisnis, seperti, katakanlah, implementasi
attachDocument()
metode dalam contoh, atau misalnya UI, pencatatan atau kode basis data secara umum. Sementara satu cara untuk menegakkan pemisahan ini adalah dengan "kode lunak" semua logika bisnis dalam file konfigurasi, ini jauh dari satu-satunya metode (atau yang terbaik).Kode logika bisnis seperti itu juga harus ditulis dengan cukup jelas sehingga, jika Anda menunjukkannya kepada pakar domain bisnis tanpa keterampilan pengkodean, mereka akan dapat memahaminya. Paling tidak, jika dan ketika persyaratan bisnis berubah, kode yang mengkodekannya harus cukup jelas sehingga bahkan seorang programmer baru tanpa familier dengan basis kode harus dapat dengan mudah menemukan, meninjau dan memperbarui logika bisnis, dengan asumsi bahwa tidak diperlukan fungsionalitas baru secara kualitatif.
Idealnya, kode tersebut juga akan ditulis dalam bahasa khusus domain untuk menegakkan pemisahan antara logika bisnis dan infrastruktur yang mendasarinya, tetapi itu mungkin tidak perlu rumit untuk aplikasi in-house dasar. Yang mengatakan, jika Anda misalnya menjual perangkat lunak kepada banyak klien yang masing-masing memerlukan seperangkat aturan bisnis kustom mereka sendiri, bahasa scripting khusus domain sederhana (mungkin misalnya berdasarkan pada kotak pasir Lua ) mungkin saja masalahnya.
sumber