Saya menikmati teka-teki jigsaw yang bagus seperti halnya orang berikutnya. Ada sesuatu yang memuaskan saat memulai dengan setumpuk potongan yang tampaknya acak dan menyaksikan gambar itu perlahan-lahan merenggut nyawa saat Anda memulihkan ketertiban dalam kekacauan.
Namun, saya berhenti mengerjakan teka-teki jigsaw. Sudah mungkin, oh, 13 tahun sekarang. Biarkan aku melakukan matematika. Saya punya empat anak; yang tertua berusia 15 tahun. Ya, usia dua tahun tepat ketika dia cukup umur untuk mengembara ke teka-teki yang belum selesai, melarikan diri dengan salah satu potongan, dan memberinya makan ke anjing atau mesin pemanas atau toilet.
Dan sama memuaskannya dengan menempatkan potongan terakhir ke dalam teka-teki jigsaw, menempatkan potongan terakhir dari belakang ke dalam teka-teki dan menyadari bahwa potongan terakhir tidak ada adalah hal yang sangat menghancurkan.
Itulah yang saya rasakan tentang kode penanganan kesalahan saya.
VbWatchdog's Variables Inspector
Jika Anda menggunakan vbWatchdog untuk penanganan kesalahan Anda (Anda harus melakukannya), maka Anda harus terbiasa dengan salah satu fitur yang paling kuat:Inspektur Variabel. Objek ini menyediakan akses ke setiap variabel dalam cakupan di setiap tingkat tumpukan panggilan. Tingkat detail itu adalah emas digital ketika tiba saatnya untuk memecahkan masalah bug.
Selama bertahun-tahun, saya telah mengembangkan modul penanganan kesalahan tingkat lanjut yang mencatat semua informasi ini. Saat saya menyempurnakan penanganan kesalahan saya, satu cacat mulai menonjol. Meskipun saya dapat mengekstrak nilai dari sebagian besar variabel saya, yang bisa saya dapatkan dari variabel objek hanyalah 'Tidak Ada' atau '{Object}'.
Ini bukan ketukan pada vbWatchdog. Sebuah objek bisa berupa apa saja. Nilai lain apa yang mungkin ditunjukkannya? Tetap saja, potongan puzzle yang hilang ini menggerogotiku. Saya bisa merasakan alam semesta menertawakan saya ketika saya memecahkan masalah beberapa bug dan kunci untuk menyelesaikannya tersembunyi di balik satu kata malu-malu yang menjengkelkan, '{Object}'.
Andai saja saya memiliki cara untuk mengetahui satu atau dua sifat pengidentifikasi objek itu, saya dapat mengetahui dengan tepat apa yang sedang terjadi.
Percobaan pertama
Upaya pertama saya untuk memecahkan masalah adalah alat bantu setiap programmer yang frustrasi:brute force. Di penangan kesalahan global saya, saya menambahkan Select...Case pernyataan di sekitar .TypeDesc
.
Misalnya, saya memiliki kelas pembuat SQL yang saya sebut clsSQL . Salah satu properti di kelas itu adalah .LastSQL
. Properti itu berisi pernyataan SQL terakhir yang dibuat atau dieksekusi oleh kelas. Itu bisa berupa pernyataan SELECT atau INSERT/UPDATE/DELETE/etc. (Saya meminjam ide dari objek DAL web2py. )
Berikut adalah sebagian dari penangan kesalahan global saya:
Select Case .TypeDesc
Case "clsSQL"
If Not .Value Is Nothing Then
ThisVar = .Name & ".LastSQL = " & .Value.LastSQL
End If
Seiring waktu saya mulai menambahkan jenis objek kustom tambahan ke daftar ini. Dengan setiap jenis kustom, saya perlu mengambil properti kustom yang berbeda.
Saya memiliki potongan terakhir saya untuk teka-teki. Masalahnya adalah saya menemukannya mengambang di mangkuk air anjing, semua dikunyah di satu sisi. Saya kira Anda bisa mengatakan bahwa teka-teki saya telah selesai, tetapi itu adalah kemenangan Pyrrhic.
Penyembuhan yang lebih banyak merugikan daripada manfaatnya
Saya segera menyadari bahwa solusi ini tidak akan berskala. Ada banyak masalah. Pertama, kode penanganan kesalahan global saya akan membengkak. Saya menyimpan kode penanganan kesalahan saya dalam satu modul standar di dalam pustaka kode saya. Itu berarti kapan pun saya ingin menambahkan dukungan untuk modul kelas, kode itu akan ditambahkan ke setiap proyek saya. Itu benar bahkan jika modul kelas hanya digunakan dalam satu proyek.
Masalah berikutnya adalah saya memperkenalkan dependensi eksternal ke dalam kode penanganan kesalahan saya. Bagaimana jika saya mengubah clsSQL saya? class suatu hari nanti dan ganti nama atau hapus .LastSQL
metode? Seberapa besar kemungkinan saya akan menyadari bahwa ketergantungan seperti itu ada saat saya bekerja di clsSQL . saya? kelas? Pendekatan ini akan cepat runtuh karena bobotnya sendiri kecuali saya menemukan alternatif.
Mencari solusi Python
Saya menyadari bahwa yang sebenarnya saya inginkan adalah suatu cara untuk menentukan representasi kanonik suatu objek dari dalam objek itu . Saya ingin dapat menerapkan representasi ini sesederhana atau serumit yang diperlukan. Saya ingin cara untuk menjamin bahwa itu tidak akan meledak saat runtime. Saya ingin ini sepenuhnya opsional untuk setiap modul kelas.
Ini sepertinya daftar keinginan yang panjang, tetapi saya dapat memenuhi setiap item di dalamnya dengan solusi yang saya temukan.
Sekali lagi, saya meminjam ide dari Python. Semua objek python memiliki properti khusus yang dikenal sebagai ._repr
. Properti ini adalah representasi string dari objek. Secara default, ini akan mengembalikan nama tipe dan alamat memori dari instance objek. Namun, programmer Python dapat mendefinisikan .__repr__
metode untuk mengganti perilaku default. Ini adalah bagian menarik yang saya inginkan untuk kelas VBA saya.
Saya akhirnya menemukan solusi ideal saya. Sayangnya, saya menemukannya dalam bahasa lain di mana solusinya sebenarnya adalah fitur dari bahasa itu sendiri . Bagaimana itu bisa membantu saya di VBA? Ternyata ide adalah bagian yang penting; Saya hanya perlu sedikit kreatif dengan penerapannya.
Antarmuka untuk menyelamatkan
Untuk menyelundupkan konsep Python ini ke VBA, saya beralih ke fitur bahasa yang jarang digunakan:antarmuka dan operator TypeOf. Begini cara kerjanya.
Saya membuat modul kelas yang saya beri nama iRepresentation . Antarmuka di sebagian besar bahasa diberi nama dengan "i" di depan menurut konvensi. Tentu saja, Anda dapat memberi nama modul apa pun yang Anda suka. Berikut adalah kode lengkap untuk iRepresentation saya kelas.
iRepresentation.cls
`--== iRepresentation ==-- class module
Option Compare Database
Option Explicit
Public Property Get Repr() As String
End Property
Saya harus menunjukkan bahwa tidak ada yang istimewa tentang modul kelas yang berfungsi sebagai antarmuka di VBA. Maksud saya, tidak ada kata kunci level modul atau atribut tersembunyi yang perlu kita atur. Kami bahkan dapat membuat instance objek baru menggunakan tipe ini, meskipun tidak ada gunanya (satu pengecualian adalah pengujian, tetapi itu adalah topik untuk hari yang berbeda). Misalnya, berikut ini akan menjadi kode yang valid:
Dim Representation As iRepresentation
Set Representation = New iRepresentation
Debug.Print Representation.Repr
Sekarang, katakanlah saya memiliki modul kelas khusus bernama oJigsawPuzzle . Modul kelas memiliki beberapa properti dan metode, tetapi kami menginginkan satu yang akan membantu kami mengidentifikasi objek JigsawPuzzle mana yang sedang kami tangani ketika kesalahan muncul. Salah satu kandidat yang jelas untuk pekerjaan semacam itu adalah SKU, yang secara unik mengidentifikasi teka-teki itu sebagai produk di rak-rak toko. Tentu saja, tergantung pada situasi kami, kami mungkin ingin menyertakan informasi lain dalam perwakilan kami juga.
oJigsawPuzzle.cls
'--== oJigsawPuzzle ==-- class module
Option Compare Database
Option Explicit
Implements iRepresentation ' <-- We need this line...
Private mSKU As String
Private mPieceCount As Long
Private mDesigner As String
Private mTitle As String
Private mHeightInInches As Double
Private mWidthInInches As Double
'... and these three lines
Private Property Get iRepresentation_Repr() As String
iRepresentation_Repr = mSKU
End Property
Di sinilah keajaiban masuk. Saat kita mengerjakan objek Variables Inspector, sekarang kita dapat menguji setiap variabel objek untuk melihat apakah variabel tersebut mengimplementasikan antarmuka ini. Dan, jika ya, kita dapat mengambil nilai tersebut dan mencatatnya bersama dengan nilai variabel lainnya.
Kutipan penanganan kesalahan
' --== Global Error Handler excerpt ==--
'Include Repr property value for classes that
' implement the iRepresentation interface
If TypeOf .Value Is iRepresentation Then
Dim ObjWithRepr As iRepresentation
Set ObjWithRepr = .Value
ThisVar = .Name & ".Repr = " & ObjWithRepr.Repr
End If
Dan dengan itu, teka-teki penanganan kesalahan saya sekarang selesai. Semua bagian diperhitungkan. Tidak ada bekas gigitan. Tidak ada bagian yang terkelupas. Tidak ada ruang kosong.
Saya akhirnya memulihkan ketertiban dalam kekacauan.