Session E-INST

Instrumenting Visual FoxPro Applications

Rod Paddock
Dash Point Software, Inc


Introduction

There have been numbers presented that say 80% of the cost and time spent developing software consists of primarily maintenance. It should be the goal of all developers to reduce these costs to the lowest point possible. You can reduce your development costs in a number of ways: using OOP development techniques, having standards and documenting your designs well. There is on often overlooked way to lower the costs: How about removing functionality ??? In this session you will learn how you can lower your development costs by instrumenting your applications and removing unused system functionality.

In this session you will learn:

What is Instrumenting

Instrumentation is a method of adding code to your software to analyze its usage. Instrumentation is commonly used in the debugging process. Developers use instrumentation to make sure all aspects of their software are being tested. In development instrumentation can also be called Profiling or Coverage Analysis. Commonly this is where the analysis of usage stops. Once the application reaches production its usage is not examines except where there are enhancements being made of bugs being fixed.

Instrumentation is the process of analyzing production or runtime usage of software. This technique utilizes code that tracks how the system is being used at specific application junctures. This code is much like profiling code in that it records information such as the time a function was run, who was running that function and what was being run. Where it differs is that profiling tracks each and every line of code being run, instrumentation works at a higher level looking for application functionality being used. It wants to know things like: what forms are being run, what menus options are being hit and what buttons are being pressed. With this information developers can make educated decisions on what functionality to keep and upgrade and what functionality to remove.

How to Instrument your Applications

The instrumentation process begins with determining what types of things you want to track. The easiest place to look for the answer to this problem is the Windows 95 interface guidelines. The Windows 95 guidelines contain 7 basic rules of user interface design. The first rule says:

“Applications should follow the object-action paradigm.”

What this rule means is when people activate menu bars something should happen or when a user presses a button some action should occur. With this in mind you can see that you should at least instrument your application from its menus and its command buttons. However in a Windows environment other actions that might occur include: form switching when multiple forms are active, selection of options from a list box, screen changes from a combo or list box, or even activating screens from check boxes (Remember 2.6?).

With this in mind you can go to work instrumenting your applications. For this session you will look at instrumenting command buttons, menus and forms.

Instrumenting Menus

The first items to look at instrumenting are menus. Most application components are launched from some type of system menu so this is a good place to begin your instrumentation. When you instrument your menus you have a few options as to where you stick your instrumentation code. You can stick the code in your menu bars directly or you can stick the code in your global application object that is responsible for launching forms and programs. In either case your code will track the same information, what menu option was pressed. The following code represents a function that will track the proper information for instrumenting menus:

*-- This function instruments menus.
Function g_insmnu
Lparameters pcPrompt, pcPad
 
*-- Open instrumentation file
If Not Used("Instrument")
  Use Instrument In 0
Endif
 
*-- Get the text from the menu pad
Local lcPadPrompt
lcPadPrompt = prmpad("_msysmenu",pcPad)
 
Insert Into Instrument (calling_source, ;
  program_name, other_name, call_date, call_time) ;
Values ;
  ("MENU", pcPrompt, lcPadPrompt, date(), time())
 
Return 

Upon completing this function you can insert the calls to this function into your menu bars with the following command:

g_insmnu(Prompt(), Pad())

This call  will insert a record into the instrumentation data table. Other useful information that you might want to track might include: user information (who is running this function) or maybe profiling statistics.

Instrumenting Command Buttons

The next item on the list is code to track command button hits. Instrumenting command buttons should be rather simple. All you need to do is place code into your command button base class and all of your buttons will instrumented. The code for instrumenting command buttons is as follows:

*-- This function instruments a command button
Function g_inscmd
Lparameters poCommandButton, poForm
 
*-- Open instrumentation file
If Not Used("Instrument")
  Use Instrument In 0
Endif
 
Insert Into Instrument (calling_source, ;
  program_name, other_name, call_date, call_time) ;
Values ;
  ("CMD", poCommandButton.caption, poform.Caption, date(), time())
 
Return

This code accepts two parameters. The object itself and a handle to the form the object is on. To call this function place the following call into your command buttons base class:

g_inscmd(This,Thisform)

Another item that you might want to consider tracking in this instance is the picture property of the button. If you use graphical buttons with no text you will need to track this additional property.

Instrumenting Forms

The last item to instrument are forms. Forms pose a unique problem in that they can be called from so many different paths. You can open forms as part of a form set, you can create multiple instances of a form or you can switch between multiple open forms.  The following code show how you can instrument forms. Pay attention to the SYS(16) function. This function moves up the calling stack to see where this form was called from.

*-- This function instruments forms
Function g_insfrm
Lparameters poForm
 
*-- Open instrumentation file
If Not Used("Instrument")
  Use Instrument In 0
Endif
 
Insert Into Instrument (calling_source, ;
  program_name, other_name, call_date, call_time) ;
Values ;
  ("FRM", poForm.caption, SYS(16,1), ;
    date(), time())

Return

To run this code stick the following call into the Activate, Deactivate and Init methods of your form base class:

g_insfrm(Thisform)

Other useful information you might want to call from here may include: The number of forms opened (from the application.forms property), the event that was actually called and time open information for a specific form.

Analyzing The Results

After tracking this information you need to look at it with a critical eye. This critical eye should be looking for the following items: What are the most used application components and how many times are they being run.

At the highest level you can begin looking at the menus. This is where the wealth of your information can be derived from. Menus tell you what application components are being used at the highest level. More granular data comes from forms, command buttons and other lower level components. The following query looks at menu usage:

Select program_name as prompt, other_name as pad , sum(1) as menucount ;
  From Instrument ;
Where calling_source = "MENU" ;
Group By 2,1 ;
Order By 3 Descending ;
Into Cursor c_menucalls

The next query looks at command button usage.

Select program_name as button,other_name as form ,sum(1) as menucount ;
  From Instrument ;
Where calling_source = "CMD" ;
Group By 2,1 ;
Order By 3 Descending ;
Into Cursor c_buttoncalls

Now that you have this information what do you do with it ? The first thing you need to consider is: Was my instrumentation period adequate. You want to make sure that you have a “real” representation of how your application is used over time. Make sure you have instrumented your application with enough time for periodic functions to be run, you know: Month-End…

Upon finding functionality that is not being used you should begin by placing “stub” code in your application to temporarily disable functionality. This code should tell users how to contact IS to re-enable this functionality.

After a time you can remove any functionality that has not been specifically requested by a user.

Further Thoughts on Instrumentation

So far you have looked at the functionality that was called. Another important item you would like to know is what didn’t the users run. How do you do this ? To accomplish this you need to create code that will create the universe of options that are available to users. The simplest place to look is menus.  As a future exercise you can create a program that will take a MNX file and dissect into its various components that you can then use to coordinate with your Instrumentation data.

Where it gets rather difficult is when it comes for forms and command buttons. It could be rather hard to create a universe of data from these files without creating a parsing program for projects. The simplest method for tacking these files is to put a button on your base form class and to regressively test your application. On each form the tester should press this button which will then register all objects on a form with a universe table.

This is the current set of problems that this author is working on. For future information on this topic look at www.dashpoint.com.

Conclusion

As you can see there is real value in instrumenting your applications. You can find out what people are really using and remove functionality that is not being used.  In this session you learned: