Bagaimana saya bisa menulis fungsi yang dapat digunakan kembali tanpa mengorbankan kinerja? Saya berulang kali menghadapi situasi di mana saya ingin menulis fungsi dengan cara yang membuatnya dapat digunakan kembali (misalnya tidak membuat asumsi tentang lingkungan data) tetapi mengetahui keseluruhan aliran program saya tahu itu bukan yang paling efisien metode. Sebagai contoh jika saya ingin menulis fungsi yang memvalidasi kode stok tetapi dapat digunakan kembali saya tidak bisa hanya berasumsi bahwa recordset terbuka. Namun, jika saya membuka dan menutup recordset setiap kali fungsi dipanggil maka kinerja hit ketika perulangan melalui ribuan baris bisa sangat besar.
Jadi untuk kinerja saya mungkin punya:
Function IsValidStockRef(strStockRef, rstStockRecords)
rstStockRecords.Find ("stockref='" & strStockRef & "'")
IsValidStockRef = Not rstStockRecords.EOF
End Function
Tetapi untuk dapat digunakan kembali, saya membutuhkan sesuatu seperti berikut:
Function IsValidStockRef(strStockRef)
Dim rstStockRecords As ADODB.Recordset
Set rstStockRecords = New ADODB.Recordset
rstStockRecords.Open strTable, gconnADO
rstStockRecords.Find ("stockref='" & strStockRef & "'")
IsValidStockRef = Not rstStockRecords.EOF
rstStockRecords.Close
Set rstStockRecords = Nothing
End Function
Saya khawatir bahwa dampak pada kinerja membuka dan menutup recordset itu ketika dipanggil dari dalam loop lebih dari ribuan baris / catatan akan parah tetapi menggunakan metode pertama membuat fungsi tersebut kurang dapat digunakan kembali.
Apa yang harus saya lakukan?
sumber
Jawaban:
Anda harus melakukan apa pun yang menghasilkan nilai bisnis yang lebih besar dalam situasi ini.
Menulis perangkat lunak selalu merupakan trade-off. Hampir tidak pernah semua tujuan yang valid (rawatan, kinerja, kejelasan, keringkasan, keamanan dll.) Sepenuhnya selaras. Jangan jatuh ke dalam perangkap orang-orang yang berpandangan pendek yang menganggap salah satu dari dimensi ini sebagai yang terpenting dan meminta Anda untuk mengorbankan segalanya untuk itu.
Alih-alih, pahamilah risiko apa dan manfaat apa yang ditawarkan masing-masing alternatif, ukurlah risiko itu dan ikuti risiko yang memaksimalkan hasilnya. (Anda tidak harus benar-benar membuat estimasi numerik, tentu saja. Ini cukup untuk mempertimbangkan faktor-faktor seperti "menggunakan kelas ini berarti mengunci kita ke dalam algoritma hash, tetapi karena kita tidak menggunakannya untuk menjaga terhadap serangan berbahaya , hanya untuk kenyamanan, yang satu ini cukup baik sehingga kita bisa mengabaikan peluang 1: 1.000.000.000 tabrakan tidak sengaja ".)
Yang paling penting adalah untuk mengingat bahwa mereka adalah kompromi; tidak ada satu prinsip pun yang membenarkan segala sesuatu untuk memuaskan, dan tidak ada keputusan, sekali diambil, perlu berdiri selamanya . Anda mungkin harus selalu merevisi ke belakang ketika keadaan berubah dengan cara yang tidak Anda perkirakan. Itu menyebalkan, tapi tidak separah membuat keputusan yang sama tanpa melihat ke belakang.
sumber
Tak satu pun dari ini tampaknya lebih dapat digunakan kembali daripada yang lain. Mereka sepertinya berada pada level abstraksi yang berbeda . Yang pertama adalah untuk memanggil kode yang memahami sistem stok cukup dekat untuk mengetahui bahwa memvalidasi referensi stok berarti melihat melalui
Recordset
dengan semacam permintaan. Yang kedua adalah untuk memanggil kode yang hanya ingin tahu apakah kode stok valid atau tidak dan tidak tertarik dengan dirinya sendiri tentang bagaimana Anda memverifikasi hal itu.Tapi seperti kebanyakan abstraksi , ini "bocor". Dalam hal ini abstraksi bocor melalui kinerjanya - kode panggilan tidak dapat sepenuhnya mengabaikan bagaimana validasi diterapkan karena jika itu dilakukan, ia mungkin memanggil fungsi itu ribuan kali seperti yang Anda gambarkan dan secara serius menurunkan kinerja keseluruhan.
Pada akhirnya, jika Anda harus memilih antara kode yang tidak diabstraksi dengan buruk dan kinerja yang tidak dapat diterima, Anda harus memilih kode yang tidak diabstraksikan dengan buruk. Tetapi pertama-tama, Anda harus mencari solusi yang lebih baik - kompromi yang mempertahankan kinerja yang dapat diterima dan menghadirkan abstraksi yang layak (jika tidak ideal). Sayangnya saya tidak terlalu mengenal VBA, tetapi dalam bahasa OO, pikiran pertama saya adalah memberikan kode panggilan kelas dengan metode seperti:
Di sini metode
Begin...
dan AndaEnd...
melakukan manajemen siklus satu kali dari set rekaman,IsValidStockRef
cocok dengan versi pertama Anda, tetapi menggunakan set rekaman ini yang bertanggung jawab atas kelas itu, daripada menyerahkannya. Kode panggilan kemudian akan memanggilBegin...
danEnd...
metode di luar loop, dan metode validasi di dalam.Catatan: Ini hanya contoh ilustrasi yang sangat kasar, dan mungkin dianggap sebagai umpan pertama di refactoring. Nama-nama mungkin dapat menggunakan tweaking, dan tergantung pada bahasanya harus ada cara yang lebih bersih atau idiomatis untuk melakukannya (C # misalnya dapat menggunakan konstruktor untuk memulai dan
Dispose()
mengakhiri). Idealnya kode yang hanya ingin memeriksa apakah referensi stok valid seharusnya tidak harus melakukan manajemen siklus hidup sama sekali.Ini mewakili sedikit degradasi ke abstraksi yang kami sajikan: sekarang memanggil kode perlu tahu cukup tentang validasi untuk memahami bahwa itu adalah sesuatu yang memerlukan semacam pengaturan dan teardown. Tetapi sebagai imbalan atas kompromi yang relatif sederhana ini, kami sekarang memiliki metode yang dapat digunakan dengan mudah dengan memanggil kode, tanpa mengganggu kinerja kami.
sumber
BeginValidation
,,EndValidation
danIsValidStockRef
memiliki hubungan khusus satu sama lain. Pengetahuan tentang hubungan itu lebih kompleks daripada pengetahuan yang diperlukan untuk menangani secara langsung aRecordSet
. Dan pengetahuan yang dibutuhkan untuk menanganiRecordSet
lebih luas berlaku.using
pernyataan untuk melakukan pekerjaan ini. Dalam bahasa lain (yang tetap menggunakan pengecualian), untuk melakukan pekerjaan yang sama denganusing
, Anda harus menggunakantry {} finally {}
untuk menjamin pembuangan yang benar, dan bahkan terkadang tidak mungkin untuk membungkus semua kode dengan benarthrow
. Ini adalah masalah potensial dengan semua solusi yang disebutkan di sini, dan saya juga tidak yakin bagaimana ini harus diselesaikan dalam VBA.Untuk waktu yang lama, saya menerapkan sistem pemeriksaan yang rumit untuk dapat menggunakan transaksi basis data. Logika transaksi berjalan sebagai berikut: membuka transaksi, melakukan operasi database, kembalikan pada kesalahan atau komit pada kesuksesan. Komplikasi datang dari apa yang terjadi ketika Anda ingin operasi tambahan dilakukan dalam transaksi yang sama. Anda harus menulis metode kedua sepenuhnya yang melakukan kedua operasi, atau Anda dapat memanggil metode asli Anda dari satu detik, membuka transaksi hanya jika salah satu belum dibuka dan melakukan / mengembalikan perubahan hanya jika Anda adalah satu untuk membuka transaksi.
Sebagai contoh:
Harap dicatat, saya tidak menganjurkan kode di atas dengan cara apa pun. Ini harus menjadi contoh dari apa yang tidak boleh dilakukan!
Tampaknya konyol untuk membuat metode kedua untuk melakukan logika yang sama dengan yang pertama ditambah sesuatu yang ekstra, namun saya ingin dapat memanggil bagian API database dari program dan menutup masalah di sana. Namun, sementara ini sebagian menyelesaikan masalah saya, setiap metode yang saya tulis melibatkan penambahan logika verbose untuk memeriksa apakah suatu transaksi sudah terbuka, dan melakukan / mengembalikan perubahan jika metode saya membukanya.
Masalahnya adalah konseptual. Saya seharusnya tidak mencoba merangkul setiap skenario yang mungkin. Pendekatan yang tepat adalah untuk menempatkan logika transaksi dalam metode tunggal yang menggunakan metode kedua sebagai parameter yang akan melakukan logika database aktual. Logika itu menganggap transaksi terbuka dan bahkan tidak melakukan pemeriksaan. Metode-metode ini dapat dipanggil dalam kombinasi sehingga metode ini tidak berantakan dengan logika transaksi yang tidak perlu.
Alasan saya menyebutkan ini adalah karena kesalahan saya adalah berasumsi bahwa saya perlu membuat metode saya berfungsi dalam situasi apa pun. Dengan melakukan itu, saya tidak hanya dipanggil metode memeriksa apakah transaksi terbuka, tetapi juga orang-orang yang disebutnya. Dalam hal ini, ini bukan hit kinerja utama, tetapi jika mengatakan, saya perlu memverifikasi keberadaan catatan dalam database sebelum melanjutkan, saya akan memeriksa setiap metode yang memerlukannya ketika saya seharusnya hanya mengasumsikan selama itu penelepon harus dibuat sadar bahwa catatan itu harus ada. Jika metode ini dipanggil, ini adalah perilaku yang tidak terdefinisi dan Anda tidak perlu khawatir tentang apa yang terjadi.
Sebaliknya Anda harus memberikan banyak dokumentasi, dan menulis apa yang Anda harapkan benar sebelum panggilan dibuat ke metode Anda. Jika cukup penting, tambahkan itu sebagai komentar sebelum metode Anda sehingga tidak boleh ada kesalahan (javadoc memberikan dukungan yang bagus untuk hal semacam ini di java).
Saya harap itu membantu!
sumber
Anda bisa memiliki dua fungsi kelebihan beban. Dengan begitu Anda bisa menggunakan keduanya sesuai situasi.
Anda tidak bisa (saya belum pernah melihat itu terjadi) mengoptimalkan untuk semuanya, jadi Anda harus puas dengan sesuatu. Pilih yang menurut Anda lebih penting.
sumber
Optional
parameter untuk mencapai efek yang sama.2 fungsi: satu membuka recordset dan meneruskannya ke fungsi analisis data.
Yang pertama dapat dilewati jika Anda sudah memiliki recordset terbuka. Yang kedua dapat mengasumsikan bahwa itu akan melewati recordset terbuka, mengabaikan dari mana asalnya, dan memproses data.
Anda memiliki kinerja dan daya guna kembali!
sumber
Optimasi (selain optimasi mikro) secara langsung bertentangan dengan modularitas.
Modularitas bekerja dengan mengisolasi kode dari konteks globalnya, sedangkan optimasi kinerja mengeksploitasi konteks global untuk meminimalkan apa yang harus dilakukan oleh kode. Modularitas adalah manfaat kopling rendah, sedangkan (potensi untuk) kinerja sangat tinggi adalah manfaat kopling tinggi.
Jawabannya adalah arsitektur. Pertimbangkan potongan-potongan kode yang ingin Anda gunakan kembali. Mungkin komponen perhitungan harga, atau logika validasi konfigurasi.
Maka Anda harus menulis kode yang berinteraksi dengan komponen itu untuk dapat digunakan kembali. Di dalam komponen di mana Anda tidak pernah dapat menggunakan hanya bagian dari kode Anda dapat mengoptimalkan kinerja karena Anda tahu tidak ada orang lain yang akan menggunakannya.
Caranya adalah menentukan apa komponen Anda.
tl; dr: antara komponen menulis dengan modularitas dalam pikiran, dalam komponen menulis dengan kinerja dalam pikiran.
sumber