sql >> Database teknologi >  >> RDS >> Access

Fejlhåndtering på kandidatniveau

Jeg nyder et godt puslespil lige så meget som den næste fyr. Der er noget tilfredsstillende ved at starte med en bunke tilsyneladende tilfældige stykker og se billedet langsomt tage liv, mens du genopretter orden i kaosset.

Jeg holdt dog op med at lave puslespil. Det er nok, åh, 13 år siden. Lad mig regne ud. Jeg har fire børn; den ældste er 15.  Ja, to år gammel er lige på det tidspunkt, hvor hun var gammel nok til at vandre op til et ufærdigt puslespil, forsvinde med en af ​​brikkerne og fodre den til hunden eller varmeapparatet eller toilettet.

Og lige så tilfredsstillende som det er at placere den sidste brik i et puslespil, så er det lige så sjæleknusende at placere den næstsidste brik i puslespillet og indse, at den sidste brik mangler.

Sådan plejede jeg at have det med min fejlhåndteringskode.

vbWatchdog's Variable Inspector

Hvis du bruger vbWatchdog til din fejlhåndtering (det burde du), så bør du være bekendt med en af ​​dens mest kraftfulde funktioner:Variables Inspector. Dette objekt giver adgang til hver variabel i omfanget på hvert niveau af opkaldsstakken. Det detaljeringsniveau er digitalt guld, når det er tid til at fejlfinde fejl.

Gennem årene har jeg udviklet et avanceret fejlhåndteringsmodul, der logger alle disse oplysninger. Da jeg finjusterede min fejlhåndtering, begyndte en plet at skille sig ud. Selvom jeg kunne udtrække værdierne af de fleste af mine variabler, var alt, hvad jeg nogensinde kunne få ud af objektvariabler, enten 'Intet' eller '{Object}'.

Dette er ingen bank på vbWatchdog. En genstand kan være hvad som helst. Hvilken anden værdi kunne det vise? Alligevel nagede denne manglende brik i puslespillet mig. Jeg kunne mærke universet grine af mig, da jeg fejlfindede en eller anden fejl, og nøglen til at ordne det var gemt bag det ene sindssygt kedelige ord, '{Object}'.

Hvis bare jeg havde en måde at kende en eller to af de identificerende egenskaber ved det objekt, kunne jeg finde ud af præcis, hvad der foregik.

Første forsøg

Mit første forsøg på at løse problemet er enhver frustreret programmørs go-to-værktøj:brute force. I min globale fejlhåndtering tilføjede jeg en Vælg...Case sætning omkring .TypeDesc .

For eksempel har jeg en SQL builder-klasse, som jeg kalder clsSQL . En af egenskaberne i den klasse er .LastSQL . Denne egenskab indeholder den sidste SQL-sætning, som klassen byggede eller udførte. Det kunne være en SELECT-sætning eller en INSERT/UPDATE/DELETE/etc. (Jeg lånte ideen fra web2pys DAL-objekt. )

Her er en del af min globale fejlhåndtering:

Select Case .TypeDesc
Case "clsSQL"
    If Not .Value Is Nothing Then
        ThisVar = .Name & ".LastSQL = " & .Value.LastSQL
    End If

Med tiden begyndte jeg at tilføje yderligere brugerdefinerede objekttyper til denne liste. Med hver tilpasset type skal jeg hente en anden tilpasset egenskab.

Jeg havde min sidste brik til puslespillet. Problemet er, at jeg fandt det svævende i hundens vandskål, alt sammen tygget op på den ene side. Man kan vel sige, at mit puslespil var komplet, men det var en pyrrhussejr.

En kur, der gør mere skade end gavn

Jeg indså hurtigt, at denne løsning ikke ville skalere. Der var mange problemer. For det første ville min globale fejlhåndteringskode blive oppustet. Jeg opbevarer min fejlhåndteringskode i et enkelt standardmodul i mit kodebibliotek. Det betyder, at hver gang jeg ønskede at tilføje understøttelse af et klassemodul, ville den kode blive tilføjet til hvert eneste af mine projekter. Det var sandt, selvom klassemodulet kun blev brugt i et enkelt projekt.

Det næste problem er, at jeg introducerede eksterne afhængigheder i min fejlhåndteringskode. Hvad hvis jeg ændrede min clsSQL klasse en dag og omdøb eller fjern .LastSQL metode? Hvad er chancerne for, at jeg ville indse, at en sådan afhængighed eksisterede, mens jeg arbejdede i min clsSQL klasse? Denne tilgang ville hurtigt kollapse under sin egen vægt, medmindre jeg fandt ud af et alternativ.

Søger Python efter en løsning

Jeg indså, at det, jeg virkelig ønskede, var en måde at bestemme en kanonisk repræsentation af et objekt indefra det objekt . Jeg ønskede at kunne implementere denne repræsentation så enkelt eller komplekst som nødvendigt. Jeg ville have en måde at garantere, at den ikke ville sprænge i luften under kørsel. Jeg ønskede, at det skulle være helt valgfrit for hvert klassemodul.

Dette virker som en lang ønskeseddel, men jeg var i stand til at tilfredsstille hvert punkt på den med den løsning, jeg fandt.

Endnu en gang lånte jeg en idé fra Python. Python-objekter har alle en speciel egenskab kendt som ._repr . Denne egenskab er strengrepræsentationen af ​​objektet. Som standard vil det returnere typenavnet og hukommelsesadressen for objektforekomsten. Python-programmører kan dog definere en .__repr__ metode til at tilsidesætte standardadfærden. Dette er den saftige smule, jeg ville have til mine VBA-timer.

Jeg fandt endelig min ideelle løsning. Desværre fandt jeg det på et andet sprog, hvor løsningen faktisk er en funktion i selve sproget . Hvordan skulle det hjælpe mig i VBA? Det viser sig, at ideen var den vigtige del; Jeg skulle lige være lidt kreativ med implementeringen.

Grænseflader til redningen

For at smugle dette Python-koncept ind i VBA, vendte jeg mig til en sjældent brugt funktion i sproget:grænseflader og TypeOf-operatøren. Sådan fungerer det.

Jeg oprettede et klassemodul, som jeg kaldte iRepresentation . Grænseflader på de fleste sprog er navngivet med et førende "i" efter konvention. Du kan selvfølgelig navngive dine moduler, hvad du vil. Her er den fulde kode til min iRepresentation klasse.

iRepresentation.cls

`--== iRepresentation ==-- class module
Option Compare Database
Option Explicit

Public Property Get Repr() As String
End Property

Jeg skal påpege, at der ikke er noget særligt ved et klassemodul, der fungerer som en grænseflade i VBA. Med det mener jeg, at der ikke er noget modulniveau nøgleord eller skjult egenskab, som vi skal indstille. Vi kan endda instansiere et nyt objekt ved hjælp af denne type, selvom der ikke ville være meget af en mening (en undtagelse er test, men det er et emne for en anden dag). For eksempel ville følgende være gyldig kode:

Dim Representation As iRepresentation
Set Representation = New iRepresentation

Debug.Print Representation.Repr

Lad os nu sige, at jeg har et brugerdefineret klassemodul ved navn oJigsawPuzzle . Klassemodulet har flere egenskaber og metoder, men vi vil have en, der hjælper os med at identificere, hvilket JigsawPuzzle-objekt, vi har at gøre med, når der opstår en fejl. En oplagt kandidat til et sådant job er SKU'en, som unikt identificerer puslespillet som et produkt på butikshylderne. Afhængigt af vores situation kan vi naturligvis også inkludere andre oplysninger i vores repræsentation.

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

Det er her, magien kommer ind.  Når vi arbejder os gennem Variables Inspector-objektet, kan vi nu teste hver enkelt objektvariabel for at se, om den implementerer denne grænseflade. Og hvis det gør det, kan vi gribe den værdi og logge den sammen med resten af ​​vores variabelværdier.

Fejlhåndteringsuddrag

' --== 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

Og dermed er mit fejlhåndteringspuslespil nu fuldført. Der er redegjort for alle brikker. Der er ingen bidemærker. Ingen af ​​stykkerne skaller fra hinanden. Der er ingen tomme pladser.

Jeg har endelig genoprettet ro og orden i kaosset.


  1. WHERE IN-tilstand accepterer ikke strengværdi

  2. Er Oracles SYS_GUID() UUID RFC 4122 kompatibel?

  3. MySQL - Hvordan søger man efter eksakt ordmatch ved hjælp af LIKE?

  4. SQL-forespørgsel - Sammenkædning af resultater i én streng