|
SYS-CON.TV Webcasts
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
Top Links You Must Click On
Best Practices Using Properties to Make Your PowerBuilder Application More Robust
A best practice that gives developers greater control of how data is used
By: Hoyt Nelson
Jan. 18, 2007 01:45 PM
Like Java and C# programmers, PowerBuilder developers can create properties via the undocumented keyword indirect. Properties look like ordinary variables, only their value isn't accessed directly. When you declare a variable using indirect, you have to specify a function that's called when the variable is assigned (a setter) and another function that's called when the variable's value is returned (a getter).
// l_patient_id is an instance on a NVO You have to write the getter/setter functions in the same context as the indirect declaration. You cannot use indirect with "pure" global variables; in this article, "global variables" are instance variables declared on a global NVO 'g'. The getter/setter functions would be on that NVO. They can (and should) refer to a private variable:
// Accessed ONLY by the getter/setter functions so it's private Given this declaration and getter/setter then assigning to the g.l_patient_id: g.l_patient_id = 1234 is turned into a function call by the PowerBuilder compiler, in effect: g.of_set_patient_id( 1234 ) where 'g' is the name of the global NVO. Accessing the value becomes another function call, so: ll_current_patient = g.l_patient_id becomes the equivalent of: ls_current_patient = g.of_get_patient_id()
How Could Properties Be Useful? Using properties is a best practice with modern programming languages like Java and C# because they are safer than directly accessed variables. Consensus says that properties make code more robust and reliable, principally because they give the developer greater control of how the data is used. Properties are more powerful than ordinary variables because the setter/getter functions give you a hook where you can write code, e.g., to validate the data. Is there something you want to do whenever a variable changes? If you don't now you will later, and the setter function gives you a place to write the code to do that.
Example: My example comes from a legacy medical application that used a long patient ID instance on the global NVO 'g' to keep track of the current patient. The global patient ID was set and reset a couple hundred times in the application. In some contexts, there was no patient until the user selected a row, or until the code processed a row in a DataWindow. In those circumstances, the global would be set to zero to signify that there was no current patient. When the patient was selected, a new patient ID would be assigned to the global long. One problem was that another global variable needed to be kept in sync with the global patient ID. Whenever the patient ID changed, the global patient name string had to be reset too. Keeping them in sync was essential. The application perpetually displayed the current patient's name in the MicroHelp area, and it routinely displayed the global patient name on reports, without first refreshing it to make sure that it corresponded to the global patient ID. This led to bugs. We'd get support issues like "The prescription had the correct patient ID but the wrong name." Inspecting the code, I found that most of the time a change to the global patient ID was done by a call to a function that reset the patient name accordingly. However, there were a dozen patient ID assignments where that function call was missing. Bugs! There was also nothing in the application that cleared the patient's name from the MicroHelp when the patient ID was zeroed out to signify "no current patient." The MicroHelp conveyed that so-and-so was the current patient, while the application would put up messages like "You must select a patient before..." I could have simply added a reset-the-patient-name function call to the dozen places where it was missing. However, that would have left the vulnerability intact, and subsequent programmers would have had to be aware of the requirement to call the function whenever they set the patient ID. That wouldn't have done anything to fix the misleading MicroHelp that presented the current patient's name when there was no current patient. A better solution was to replace the global patient ID and patient name with properties.
Implementing the Global as a Property
// On the application object In effect, these become new global variables equivalent to the old ones that are get/set using the properties. 2. Write getter/setter functions for the new private variables. For the global patient ID:
// Patient ID Getter The patient ID setter illustrates the advantage of the property over the global variable. It provides a hook where the patient_id can be validated, especially against the ever-troublesome NULL value. The g.warn() presents its message in a console window during development and always logs the message so the developer will get a clue if some error is leading to assigning invalid patient IDs and the support team can inspect the log file when "wrong name" bugs appear. Reader Feedback: Page 1 of 1
Your Feedback
Enterprise Open Source Magazine Latest Stories . . .
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||