Reprinted with Permission by Quest Software Mar.  2002

 

A Brute Force Approach to Debugging Forms: What to do when you don't know what is happening?
Ryan Gaffuri, Bloodworth Integrated Technology

Your sitting at your desk and your manager comes over to you hands you an issue that needs to be fixed. The client is complaining because something is not working, let it be a forms crash, triggers acting improperly, or anything else. This is the kind of thing that the Oracle documentation and the books do not discuss. You have no idea what is going on. You scan Metalink and OTN to see if anyone else has had this issue and find nothing. The Oracle representative responds to your post saying that they were unable to recreate the error. You’re under time pressure. The client and your management want this fixed. What do you do? 

I start with the methodology that you can do anything with the Oracle toolset. You just have to figure out the best and most cost effective way to do it. I do not accept the concept that this is the cause of some Oracle bug and therefore cannot be done. There is a work around for everything. On my current project, I encountered a significant number of errors that were leading to forms crashing. At first we thought they were problems with the forms server. This turned out to be partially correct. There were several things that seemed to crash on the web that did not crash in client server. However, since I started with the methodology that you can do anything, I formed a specific system for tracking these kinds of bugs down. 

Advantages of this system:

  1. Meticulous: By following a simple and consistent process, you do not have to worry about missing anything. When searching for bugs it is essential that you check everything. 
  2. Process of Elimination: The basic premise is to eliminate what is not causing the problem until you reach what is causing the problem.
  3. Routine: If you do exactly the same thing every time you search for your bugs, you can then concentrate on the issue at hand. 
  4. Simple to Implement: Any developer on your team can easily implement this process. It requires little or no training and does not in anyway interfere with your development process.
  5. Your Most Junior Developers Can Use It: Since the least experienced and expensive members of your development team can follow this system and easily identify the route causes of errors, you will free up time for your more senior developers to work on other aspects of the project. 

Premises of the System:

  1. Know your Property Palette: The forms tool is based on Object-Oriented principles. Every item you place in a form has a set of properties. These properties are easily accessible by right clicking on the item in the Object-Navigator and choosing the Property Palette selection. If something is failing and you do not know why, this should be the first place you look. There is absolutely no need to memorize these properties or their functionality. Just get a basic understanding. I will often go through the property palette and hit the ‘F1’ key to get a help blurb, when I’m trying to fix a bug. 
  2. Simplify your Hunt: By eliminating what is not causing the error, you reduce the number of things that could be causing the problem and focus your search. 
  3. Work from the Baseline: Make a template form to eliminate all the clutter (triggers, program units, record groups, smart-classes, libraries) that has built up in your form over time. Then simply add the items that appear on the screen and their relationships. See if the form runs. If the form runs than you know that the basic premise of your form design is correct. If the form does not work, then you know that there is something fundamentally wrong with the form. Always check the property palette if this happens. 
  4. Use a Simple Process of Elimination: Forms operates sequentially. That means if there is a bug at a certain point in a form, the form will stop processing and display an error (or simply crash, lockup, shutdown, etc…). By eliminating items, triggers, program units, etc… and seeing whether the error still occurs you can quickly tell what is not causing the error. By eliminating all the things that are not causing the error, you will ultimately be left with what is causing the error. 
  5. Nothing is Unsolvable: There is a workaround or fix for everything. If you work from this basic premise, then it is unacceptable for a developer to say that they cannot figure out what is causing the problem. Now understanding how to fix the problem may require more thought and senior guidance. 
  6. Proper Identification is Essential: Knowing exactly where and why an error occurs is essential to efficiently solving the problem. If the problem is not identified correctly, the fix is generally inadequate. Once you have figured out what is wrong you can either solve it easily or begin the necessary research to correct the problem. I read Metalink, OTN, and PL/SQL pipeline fairly frequently and I regularly see questions from developers asking how to fix a bug. They will post these questions before they have properly analyzed and pinned down the problem. If you are not asking the correct question, you will not receive the correct answer. 

Case Study Using a Template Form:

Our application is run on the web using the form server tool. I received a write up from test regarding a forms crashing error during a simple process. I immediately went to test and asked them exactly what they did just before the forms crashed. I then went back to my desk and was successfully able to recreate the error. Instead of looking at all the trigger code and the program units and the libraries I made a simple template form that included 3 blocks in a master-detail-detail relationship. I then ran the form and followed our process. The error occurred. At this point, I knew that there was something fundamentally wrong with the form. 

I then broke all the relationships between the blocks and ran the form. The error occurred. I then deleted the detail blocks from the form. Error still occurred. I then deleted half my items from my master block. It was at this moment that the error ceased to occur. So I knew that there was something in the item(s) that I took off the screen. From here I was able to determine that one of my text items needed to be flagged as a multi-line item. If forms tried to query a multi-line row from the database and if the multi-line flag in the property palette was not set to yes, the form would crash. It never occurred to me that this simple flag would lead to a forms crashing problem, however, by simply using a template form I was able to find the problem and fix it in about 30 minutes. 

Things to identify first:

  1. Is this a data issue? Does the error occur universally or does it only happen with certain pieces of data. Make sure you recreate the error exactly the same way every time. Then try to find another record to see if it works. If it works with another record then it probably has something to do with the data. You can then do a query in the database and compare the two records. 
  2. Are your business rules correct? Some bugs are not really bugs at all. They are simply an incorrect implementation of the business rules. 

STEP 1: Your template works, but your bug is not fixed

At this point, I recommend using a forms built in feature to help you track down where the error is occurring. Go to Tools à Preferences. Click the Runtime tab and place a check mark in the debugging messages. This will popup a message and pause the form every time a trigger is fired. Pay particular attention to the last trigger fired before the error occurs. This process can get tiresome if you using a form with a large amount of triggers. There is another downside. In some of the more complex forms the error messages get caught in an infinite loop and the same message will continue to fire. (this also happens when using the forms debugging tool). Let’s your form crashes when it starts up. These messages can identify the last trigger fired before the form crashed. You can then look at the code in the trigger, look at any code that the trigger is calling, and look at the property palette of the object that is firing the trigger. Now you can simply go back and follow Premise #4 and comment out the code (or simplifying it if it’s necessary for the transaction) you can quickly identify what part(s) of the code are not causing the problem. Then you will be left with what is causing the problem. 

STEP 2: If it’s Broke… Break it even more

If your template form works properly and you were not able to narrow your search using the debugging messages, its time to literally rip your form apart. You are going to take out objects from your block until it works, then slowly put them back in until it does not work again in order to determine where it is breaking. I also recommend saving your form in various stages of disarray. Whenever objects are eliminated, code referencing those objects needs to be commented out and this can be time consuming. Due to the difficulty with commenting out code, I prefer to move as much logic from triggers to program units, so I simply have to comment out the program unit code and set it to null. 

STEP 3: Where to Start Breaking the Form? 

I have a process that I like to follow every time I break my form. However, it is not essential to do it my way. What is important is that you develop a system then do it exactly the same way every time. This way you do not have to worry about missing anything and you can focus on the problem at hand. I prefer to do this in a block-by-block format. I like to begin by breaking all the relationships between the data blocks and testing to see if the form works. Even if I’m 99% sure that this will have no effect, it is important to stick with the process. That way I know for certain that I checked everything. 

After running the form and testing it without relationships, I then start deleting detail blocks one at a time. Eventually Ill be left with my master block. I then know that the error is taking place somewhere in the master block. So, I will delete 50% of the items in the block and run the form. Does the error still occur? If it does then I know that the items I deleted did not cause the error. I then delete another 50%. Ill do this until the error ceases to occur. If the ceased to occur one of the detail blocks, Ill use the same system of deleting items from the detail block. As soon as I have deleted enough items from the block that the error ceases to occur, I move to step 4.

STEP 4: The bug hunt has been narrowed

Next Ill start adding items to the block a few at a time, until the error occurs again. As soon as the error occurs again, I know that it is related to the items I just re-added. I then pull those out one at a time, until the error ceases. When the error ceases I know that it is related to that item. This does not necessarily mean it is either a property palette issue directly related to the item, a trigger on the item, or a program unit called from a trigger on the item. It could be caused from a form, block level, or a trigger called from a button, radio button, etc… In some circumstances a property palette issue at the block or form level that is conflicting with something to do with the item. The error could also be caused from by a call from to a database object. 

The first thing I do at this point is check the property palette if something strikes me as problematic. Then I comment out all the trigger code associated with the item. If the error still occurs I know that it is either being caused from a trigger (or a program unit in the form, attached library, or in the database) or it’s a property palette issue. From here I continue to narrow my search by either commenting out code or placing messages for myself in the code to see where the code fails. 

STEP 5: Other things to consider:

  1. Use Text Items for items that return data: Text items are your bread and butter forms units. Radio groups and check boxes have some properties that are slightly different than those of a text item. It could be something as simple as not have mapped an extraneous value. You do not have to worry about this with a text item. If the text item returns the correct data and the radio button does not… then it has something to do with the property of a radio button.
  2. Make Additional Items Visible: Maybe you have a primary key that is based on a sequence and you forgot to insert the next sequence number in the key so you cannot insert…. If you make primary and foreign keys visible at runtime you will be able to quickly identify this without having to think about it. You will also want to make any other items visible that are vital to the business logic of the form. 

In Parting….

In most cases you will have an idea of what is causing the error. Whether it is a specific trigger, a transaction, a call to a database item, etc… However, this method can still be applied. I find that using a simple process of elimination helps organize my thoughts and focus my hunt. By following the same process every time, I am able to focus strictly on the problem at hand without having to worry that I missed something. The material here is hardly revolutionary. It’s simply a matter of being meticulous.