Professional Documents
Culture Documents
Best Practices Forms 9 I
Best Practices Forms 9 I
INTRODUCTION...........................................................................................4
STANDARDS ...................................................................................................4
The Importance Of Standards ....................................................................4
Coding Standards ..........................................................................................4
Naming Standards In Code.....................................................................5
How to Organize Your Code .................................................................6
Using Libraries ..........................................................................................6
Using Packages..........................................................................................7
Sharing Data Between Modules .............................................................8
Coding Style ...................................................................................................8
What about Strings? .................................................................................8
Coding for Portability ..............................................................................9
USER INTERFACE STANDARDS.............................................................9
What is Your Deployment Platform?....................................................9
Choose Your Color Palette ...................................................................10
Choose Your Coordinate System.........................................................10
Define Your Smartclasses, Visual Attributes and Property Classes 11
Define Your Template Forms Developer Modules ..........................12
Deployment Standards ...............................................................................13
HOW ADAPTABLE IS YOUR APPLICATION? ..................................13
Application Bespoking ...............................................................................14
Translation....................................................................................................14
User Memory ...............................................................................................15
APPLICATION SUPPORTABILITY ........................................................16
Monitoring The Application Remotely....................................................17
Audit Trails..............................................................................................17
Space.........................................................................................................17
The Forms Developer Transactional Model ......................................17
Performance ............................................................................................18
What Screen Is Each User Currently In..............................................18
Error Conditions.....................................................................................19
Provide An Information Option...............................................................19
Build In Debugging From The Start ........................................................20
Allow for Remote Debugging ..............................................................20
Page 2
Page 3
INTRODUCTION
This paper provides a framework and guidelines for best practices that developers
using Oracle9iAS Forms Services can adopt and adapt.. The paper does not seek
to impose a set of ideas and standards, but rather encourages you to think in a
structured and orderly way when approaching new development projects.
Within this paper well focus mainly on the issues of standards in your application
development, but well also focus on some issues that you should consider before
writing a single line of code.
STANDARDS
The Importance Of Standards
Why are standards so important? With a RAD tool such as Forms Developer, it is
simple to create Quick and Dirty screens which start out as prototypes, but
which evolve into production systems (well discuss prototyping later). If structure
and standards are not imposed on the application from the start, the end result of
the development will be inefficient, difficult to maintain and possibly bug ridden.
Sounds pretty serious? Well it is. But its all fairly simple to avoid with a bit of
planning.
We can split standards into three major areas:
Coding
UI
Deployment
Having standards in our coding practice should provide us with tangible benefits,
such as:
Page 4
Code that contains fewer bugs. As well see, good standards can
prevent many common coding bugs.
Reusable code.
If you fulfill these requirements in whatever coding standards you adopt, then you
will have succeeded. Lets look at some of the key areas for coding standards. Its
worth stressing that a comprehensive set of coding standards is beyond the scope
of this paper, so well pick and choose the highlights. However, if you want to see
more detailed standards, refer to the Further Reading section of this document.
Naming Standards In Code
Why should we want to impose naming standards? Surely this is denying the
programmer his or her right to free expression and artistry in code!
PL/SQL is a language which allows a lot (possibly too much) of freedom in
naming, both in variables and program units. There is nothing to stop you from
creating objects with the same name as a different object which exists at a different
scope. Although this can occasionally be useful, it also leads to a lot bugs which
are hard to track down as there is no logical or syntactical error. My favorite
example of this is the following snippet of Forms PL/SQL code:
DECLARE
Width NUMBER;
BEGIN
Width := to_number(
GET_WINDOW_PROPERTY(WINDOW1,WIDTH)
);
END;
The code compiles without error, but when you run it gives the error Argument 2
to Built-in cannot be null. Why? Because the local declaration of the variable
width has overridden the declaration of the Forms constant WIDTH. This
can be an even scarier problem when the value of the local variable width is
initialized to a number which happens to be a valid value as a second argument to
GET__PROPERTY. For instance, you could by chance get the HEIGHT of
the Window. You can imagine how difficult this kind of situation can be to debug.
So the key to preventing the situation in the first place is to ensure that name
collisions do not take place by enforcing naming standards. For instance, I use a
form of Hungarian notation adapted for PL/SQL use:
Datatype
Prefix (lowercase)
VARCHAR2
vc
Page 5
CHAR
PLS_INTEGER /
BINARY_INTEGER
NUMBER
BOOLEAN
DATE
ROWID
rw
The variables themselves are then names with this prefix and an init-capped
descriptive name, without any underscores.
Examples:
A VARCHAR2(20) variable for
holding a window name:
vcWindowName
iRowCount
bRC
I must stress here that the exact notation is unimportant; it is the principle of using
identifiers for objects and variables, which do not collide with existing constant
and objects at a different scope.
How to Organize Your Code
Im not going to judge where code should be located either on the server or in the
application. This is a matter that must be evaluated on a system-by-system basis,
but lets look at your coding in general.
Using Libraries
PL/SQL libraries provide a great way to organize the majority of PL/SQL coding
within your application. Some schools of thought promote the extreme of putting
no coding at all within FMB files, except stubs to call to the real code that is all
held in libraries. This can have its attractions, particularly in the situation where
you are reselling an application and want the consumer to be able to bespoke your
UI but not touch your code. However, I disagree with this idea taken to extremes.
I have seen applications where every form has its own associated library that is
unique to that form and only used by that form. Adopting this kind of regimen
just leads to module proliferation and makes maintenance harder. With the current
Page 6
versions of Forms, it will also increase memory usage if multiple users run on the
same application server due to differences in the way that memory is shared
between PLLs/PLXs and FMXs.
So, go for a happy medium - generic code should go into libraries, and code unique
to each form should stay there.
The act of putting code into libraries actually helps with re-use in itself, because
you cannot refer directly to Forms objects such as Item names. You need to
parameterize your functions to get them to compile, which implicitly makes that
function more re-usable than it would have been had it contained hardcoded
names.
Its worth mentioning the issue of indirection and parameterization at this point
since we are on the subject. In a library you cannot reference objects using bind
variable notation for example :BLOCK.ITEM. When building a function you
have two choices if you need the value of such an object:
Use Indirection, that is, use the NAME_IN() and COPY() built-ins.
Parameterize the function and pass the required value in or out using
the parameters to the program units.
Always use the latter method if possible. First, the NAME_IN() method still has a
hardcoded reference in it, so re-use can be difficult. Second, at runtime when an
indirect reference is encountered, the PL/SQL engine has to stop what it is doing
and go and look up the reference, slowing the code execution.
Finally, should you want to move the function onto the server for performance
reasons, it will stand some chance of actually working if it is parameterized and
does not have any references to Forms built-ins!
Using Packages
You want to aim for the majority of your code to be in PL/SQL packages, whether
that package is in a Form or a Library. Packages provide you with some important
advantages:
Page 7
Coding Style is one of those emotional subjects. Should programmers have the
freedom to express their own style when writing code? Unfortunately the right to
write code in an expressive way often leads to badly written and un-maintainable
code. There is no problem with elegant coding solutions but there is no excuse for
badly formatted or imprecise code!
Some issues that could be encompassed under the heading of Coding Style, and
that you need to standardize are:
Comments
Labeling of Loops
Page 8
Module Naming
User interface can mean many things; at its simplest, we think of what color our
canvas is and how high each field should be. In many cases that as far as it will go.
However, UI design consists of much, much more than this. We must consider the
applications workflow and ergonomics. For the rest of this section, I will only
mention the simplistic view of UI design and standards, and leave the other aspects
of the UI standards to usability and user interface professionals.
What is Your Deployment Platform?
Screen Size - How much real estate will you have, what resolution will the
clients be running?
Color - will all your displays support the same color resolution?
When running applications over the web you obvious have less control over what
browser the user has, or what their current screen resolution is. However, web
Page 9
deployment does remove many of the traditional problems associated with multi
GUI deployment as Java provides a standard platform for the user interface which
will render correctly on whatever O/S is being used to host the browser.
In general you should:
Test your proposed font and color standards early on. Its going to be expensive
to change your mind when user acceptance testing starts. All too often customers
have written large systems on desktop platforms without ever testing on the web
with disastrous results.
Choose Your Color Palette
Most sites will tend to stick with the default color palette provided with Forms
Developer. In some circumstances, however, you might need a custom palette.
These might include a situation when you must integrate an existing company logo
into an application and the default palette does not match the right shade of
yellow. Also, you might need to fit into an existing color scheme of the website
that the application will be called from.
You must sort out the palette before you build any real forms; palettes are very
hard to retro-fit into existing applications.
Choose Your Coordinate System
As with the color palette issue, choosing the right coordinate system is one task
that most people ignore (that is, they just use the default). What is the best
coordinate system to use? As it happens, the default of Points is actually pretty
good. The three Real coordinate systems of Points, Centimeters and Inches are
pretty much the same, and youre best picking units that make sense to you. Avoid
pixels unless you can access all the displays that the application will run on, and
you can test them. For instance, an application written using pixels might look
great on the programmers 21-inchscreen but deploy it to a 14-inch monitor
running at the same resolution and it becomes unreadable.
Avoid using character cells as a coordinate system
Coordinate system has an important side effect if you write common code
modules to handle physical layout on the screen, or you reference common reusable components. All Forms built-ins that deal with object sizing and
positioning will operate within the context of the current coordinate system. So
lets take the example of some code that re-sizes a text item. In a points-based
form, this would just be dealing with integers. In an inches-based form, it will deal
with decimal precision. Its easy to see how bugs can creep into common code as
a result.
Page 10
Choose the coordinate system early on and stick to it, making sure that the team in
charge of building generic components and common code know what it is. Its
going to be a lot easier for them to work with one target coordinate system, rather
than having to be prepared for any.
Define Your Smartclasses, Visual Attributes and Property Classes
Use Smartclasses for things you will have one of in a particular scope.
E.g. An Exit Button. Or things that you want to treat as components
which you can drag and drop from the Object Library onto a canvas.
Use Property classes where you only want a small subset of properties
inherited. For instance a button property class which just defines the
button Height and Font information
Page 11
Item
Normal
Button
Button
Iconic
Button
Text
Item
OK
Button
Small OK
Button
Cancel
Button
...
Other
Button
...
...
...
And so on...
Such hierarchies might seem attractive from a purist object-oriented point of view,
but they can get extremely complicated very quickly and if a break occurs at any
point (lets say one of the classes is inadvertently deleted or renamed) then the
consequences can be messy.
Think about defining a basic object library that contains a Smartclass (or Property
Class) for every type of widget or object that you will create. For instance,
Window Smartclasses should contain the standard window sizes for your
application. This prevents programmers from having to think too much and they
will know instantly how much real estate they will have and still fit within the
screen resolution on which you plan to deploy.
Ideally your programmers will use your object definitions for everything and will
never explicitly define a font, or pick a color for any of their objects. Then when
the day comes to change everything, the job will simply mean changing the object
library and regenerating your application.
Define Your Template Forms Developer Modules
To both speed up your module development time and to help your programmers
stick to the UI standards that you want to use, define a template module for use as
the starting point for all forms. Practicality might dictate that you actually have
more than one template for different portions of the system, but stick to the
principle.
Page 12
The template should define the coordinate system, the color palette, have standard
core libraries attached and have pre-subclassed any object groups that are required
for any common components.
Deployment Standards
We have considered some ideas about the UI for an application and how the code
should be standardized; what else is there? I want to cover two final issues on the
subject of standards, namely. Organizing the deployment of your code and coupled
with that, the change control process to be implemented.
When you build an application, you hope to create a set of files providing you with
specified functionality. But how do you deploy that?
You could of course just adopt the bucket method. Everything goes into one
directory and thats it. In practice, this only works with small systems containing a
handful of modules. For larger systems, you probably will want to divide common
code libraries from the Forms Developer modules themselves, and perhaps divide
the forms by Functional area. Once you start down this path, you then must
carefully consider the design of the directory structure, and ask the following
questions: how will my form modules find my core libraries? Where are my image
files going to reside? What environment variables must be set to get all of this to
work?
Plan a detailed diagram of your deployment model and consider the processes
associated with deployment such as:
Remember, deployment standards will vary according to your needs and the
complexity of your system, but the important thing is to think about all of these
issues.
HOW ADAPTABLE IS YOUR APPLICATION?
You have defined an application with a lovely set of standards, now what are your
customers and users going to do with it? Might there be a need to bespoke the
system in some way, either to add or change functionality, or to allow translation
into different languages? Think about these issues before you start designing. For
instance, if you plan to sell the application around the world, will that include
countries with doublebyte or Unicode character sets or screens that work right to
Page 13
left.? All of these factors will constrain and influence the standards that you set for
writing the application.
Application Bespoking
If you require that the application you are building should be bespokable (in a
supported way) by your customers, how should you achieve that?
It does of course depend on the form of bespoke coding that will occur. If the
customers only change the user interface (changing boilerplate or layouts), then
there are no major problems to consider, apart from your intellectual property with
regards to the FMB files that you will supply. You can mostly solve this problem
by encapsulating as much of your logic as possible into libraries and server side
packages. By doing this, you ensure that there is essentially no code at all in the
FMB files except for simple validation, master detail functionality and a series of
calls to code stored elsewhere.
If you want your customers to be able to extend your functionality (note: extend
not replace, if they want to replace functionality then you would presumably need
to get involved on a consultancy), then the best technique is probably to define a
user library, called from all the extendible points in the application. When you
ship your application, you would provide a user library with null implementations
of all extensions. The customer can then bespoke that user library (within the
constraints of the interfaces you have defined), and the code that they define
would automatically be called.
Translation
Creating applications that are translatable offers some extra challenges. You have
to consider three major factors:
Screen Real-estate
Variable sizes
Local Conventions
If you design your application in English, have you left enough space for your
prompts and fields to expand after translation? Lets take the trivial example of a
poplist to display the values Yes and No. In the English version the display
length of the field has to be wide enough to display three characters. In a German
implementation the equivalent of no is four characters long and would not be
fully displayed.
Remember that the screen might be displayed from right to left rather than left to
right, with the prompts, fields, etc., all reversed. You must start testing your GUI
standards very early in the design cycle if you intend to allow this.
If you are deploying to languages using double or multi-byte character sets, be
aware that when you declare VARCHAR2 variables in you code, you are, (by
default) really declaring a maximum size in bytes, not in characters. You might
Page 14
have to double or treble the actual size of the variables concerned so that they are
large enough to take the required maximum value in the relevant character set.
Fortunately the introduction of data length semantics in Forms 9i makes this
whole process simpler by allowing the size for fields and variables to be defined in
Characters rather than Bytes. For Forms Items, this uses the item property Data
Length Semantics which can be set to BYTE, CHARACTER or DEFAULT. For
variable declarations you can use the CHAR keyword as part of the variable
declaration to force a declaration to define a number of characters no matter what
character set is in use e.g.:
vcMyVar VARCHAR2(10 CHAR);
Finally, consider how conventions differ from country to country, both for
obvious items like the Currency symbol, but also for more obscure settings such as
Thousands and Decimal separators and on which day the week begins! The issue
of format masks generally can be handled simply, using the established SQL
format masks. Placeholders exist for localizable settings such as currency, which
will take effect depending on the NLS language settings. For instance L or C for
Currency, D for Decimal Separator etc.
So given a format mask of L9G999D90, the following applies:
In America
- $1,000.00
In England
- 1,000.00
In Germany - DM1.000,00
Note that in the case of the German version, the single character placeholder
expands to two characters as required.
Needless to say, you should always as a matter of course use these correct format
elements in your format masks rather than hardcode currency symbols and
separators.
If you plan to build applications to run in several different languages, then read up
on the ORA_NLS package which is supplied with Forms Developer. ORA_NLS
has functions to identify the local conventions, such as if you are running in Right
to Left, or what is the first day of the week for this locality.
User Memory
How nice do you want your application to be? If you want to provide a friendly
system that adapts to the users preferences, then youve got to think about this
from the outset. It might be as trivial as remembering where this user positioned
the windows within the application last time it was used and restoring those
positions, or it might be more complex such as calling up the last record that they
worked on. In all of these cases, its going to be simpler to engineer this kind of
functionality into the code from the start rather than trying to retro-fit it later.
Page 15
Having spent a long time in a support desk environment, I can appreciate the
importance of the Supportability within a product. What do I mean by that?
Well lets look at an example:
I am working on a Help Desk that supports a large custom application built with
Forms Developer and I get a phone call from an end user. The conversation
might go as follows:
End User: Im getting an Error in the Rent screen.
Support Person: Which Rent Screen? (Assuming that there are several Rent
related screens within the application)
End User: What do you mean? (This user only uses one of the screens so has
no concept of other parts of the system)
Support Person: Well how did you get there?
End User: Oh, from the main screen I chose the New Property menu option entered
my information and flipped to the Rent Tab.
Support Person: OK so thats the APP027 Screen. Whats the error?
End User: It says Woops! Unexpected Error.
Support Person: So what did you do before you got the error?
And well leave it there!. In an ideal world the conversation would go something
like this:
End User: Im getting an Error in the Rent screen.
Support Person: Ah yes, I see youre in the APP027 screen and have an 27056
Error - Let me look that one up. Yes your problem is that youve created a rent
agreement start date before the building was actually purchased.
End User: Oh so I have.!
Ignoring the fact that an end user shouldnt have to call up a help desk for such a
trivial validation error, this second conversation illustrates an important point.
End users should not have to deal with the systems internals. If you are going to
require information for debugging/resolving the problem, you either have to make
that information available automatically for the help desk, or provide a simple and
understandable mechanism for the end user to obtain the information.
Page 16
If you are building an in-house application where the people who are supporting
the application can access the same databases that the application uses then you
can consider logging information about the application as it is being used into the
database. You might want to log the following kinds of information:
Audit Trail
Error conditions
Audit Trails
The database itself can obviously carry out Auditing of changes made to data, but
this kind of audit is usually at too low a level to be useful in a support situation, so
most large systems would impose some kind of audit meta-model to log significant
changes to important data in an understandable way. If this is done, then when an
end user encounters an error, the support analyst or the programmer can trace the
sequence of record manipulation and hopefully learn exactly what the user did
before the problem occurred.
There are several issues with auditing applications in this way:
Space
Transaction Model
Performance
Space
If you are too enthusiastic with auditing you could easily devote more database
capacity to logging the data than the actual data itself. So imposing an auditing
mechanism also requires you to define processes to archive audit records to keep
the database space usage at a realistic level.
The Forms Developer Transactional Model
When auditing applications through Forms Services, you have the problem that a
Forms Commit is an all-or-nothing affair. If you choose to audit by using an insert
statement into the audit table on PRE- trigger, what happens if there is a failure
at commit time and the Forms transaction is rolled back? You lose the knowledge
that the user attempted an invalid transaction. This might not be a problem as no
real data was changed, but if we look at this issue from the point of view of
supporting your application, what if the user then rings up asking why they cant
insert this new record. Wouldnt it be helpful to see what they attempted to do?
How do we resolve this problem of the transactional model? There are three
solutions:
Page 17
Whether you are implementing auditing for legal or supportability reasons you do
need to ensure that it has as low an impact as possible on the applications
performance. Again the asynchronous audit strategy is ideal for this, as it can be
separate from your Forms Developer transaction and no separate commit is
required.
What Screen Is Each User Currently In?
Page 18
We want the support desk to identify exactly what module the user is in, what the
current transaction is and what the context is. As it happens, the server provides a
utility package DBMS_APPLICATION_INFO that is ideal for such use.
DBMS_APPLICATION_INFO provides a way of populating the V$SESSION
and V$SQLAREA views with context information about your application and its
behavior. There are procedures, which you can use to define the application and
module that you are currently in, and the action you are performing. You could
use your own mechanism to log this information using a technique such as the
asynchronous messaging described above. But given that
DBMS_APPLICATION_INFO feeds existing data views, which are already
visible through tools such as Oracle Enterprise Manager, it makes sense to use it
and benefit from providing a consistent and professional interface.
Once information has been logged into the V$SESSION view, all the support
person needs to know is the login of the person with a problem, and they can
instantly find the status.
Error Conditions
It goes without saying that error handling is one of the most import aspects of user
interface design. With good error handling and messaging you should be able to
prevent calls to the help desk or programmer. There will always be situations,
however, where unexpected errors occur (for instance a tablespace cant extend, or
there is some other internal server error). Traditionally, these kinds of unexpected
errors will manifest as something like Cant insert record. It is vital that enough
information is provided so that when faced with that error the support person can
quickly recognize the true implications of the error and correct it before the trickle
of calls becomes a flood.
Therefore, reporting a complete and informative error stack to the user in these
abnormal conditions is vital (or of course you could use the asynchronous
messaging option again to write the full DBMS_ERROR_TEXT to the Audit trail,
but be aware when the error is severe enough to prevent your audit mechanism
from working!)
Provide An Information Option
So what if you dont have online access to the system that you are supporting?
Obviously you want to provide an easy way for end users to give you information
about where they are in the system, what they are currently doing and what errors
they have encountered, if any. It is normal to include some kind of informational
menu option, which will pop up a dialog containing this information. You might
want to combine this with other About information, such as module versions.
Page 19
In Release 9i, Forms has the capability to allow the application developer to debug
an application that is running remotely. This is enabled by the application that is
being debugged, making a call to the built-in procedure Debug.Attach. This pops
up a dialog containing machine and port information, which the developer can
then use to attach to the problem session and debug it in situe.
This ability provides developers with a great headstart in resolving problems.
Rather than having to obtain a list of instructions from an end user on how to
cause the problem, they can simply attach, and watch the problem happen as the
user carries out the actions. As such its worth putting hooks to Debug.Attach
within all your application screens for activation as required.
However, being able to remotely debug in this way is not a panacea for the
following reasons:
The remote Debug process uses a sockets connection and cant take
place through firewalls.
As such you need to consider your options for bespoke debugging mechanisms as
well.
Bespoke Debugging
If you are building an application for deployment remotely from your support staff
and programmers, then you need to think about debugging capabilities at an early
stage in the design process. Consider incorporating some user-switchable
debugging into the application, probably from a menu option.
Debugging can take several forms. It might be as simple as issuing an ALTER
SESSION SET SQL_TRACE TRUE to get a SQL trace, or you might want to
implement a much more detailed debugging mechanism that you call at key points
throughout your application. Then if Debugging Mode is ON, the information
that you are interested in is logged either to an asynchronous messaging
mechanism like the audit trail or to a flat file on the servers hard disk, if suitable.
There is much overlap between Debugging and Auditing; often you collect the
same sorts of information about what the user is doing. The difference is that
Page 20
Once youve established your site standards and youve thought about issues such
as translation, then the real work can begin. You can start to assemble your
toolkit.
As with any programming environment, after working with Forms for a while,
most programmers will have accumulated a library of useful code snippets, or even
re-usable components. Examples of such tools might be:
Calendars
Multi-Selection dialogs
Auditing
You want to take that useful code and other generic functions that you have
identified during the design process and invest time into them so that your whole
programming effort can leverage that functionality. By getting this toolkit right,
you will save in the long run by promoting reusability.
Page 21
So far we have been thinking about PL/SQL coding but a large portion of the core
teams responsibilities will involve Forms Developer objects as well. These will
include Object Libraries to encapsulate the smart standards that youll use
throughout the application to enforce your look and feel. It will also include the
physical aspects of any pre-built components that you fit together. For instance, a
calendar widget will have a fair amount of coding behind it, but it will also consist
of Windows, Canvases and Blocks, which the end-user programmer can pick up in
the form of an Object Group to implement that component.
What Form Should The Toolkit Take?
There is no single best practice for the design of your toolkit; its depends on the
size and shape of your application. A typical application with several different
modules (modular in this context being in terms of functionality rather than in
terms of FMX files) might have the following areas of core functionality that need
to be built.
Component
Typical Functions
Core PLL
Module PLLs
Specialist Functionality
Page 22
Common Menus
Documentation
PROTOYPES
Well conclude with a few thought on prototyping. As mentioned earlier, all too
often code that starts out as a prototype to demonstrate what could be done to
fulfill user requirements becomes the production code, with additional
functionality bolted on to implement the full requirement. In order for this to
work satisfactorily, you must use the same care and diligence in constructing your
prototypes as you would for the final result. It could be argued that this defeats
the whole idea behind prototyping given that you end up embedding a large
amount of infrastructure for auditing and debugging when all that you really need
is a simple shell of an application to provide the proposed UI and a small subset of
the functionality.
From experience, the best plan for a prototype is to save some screen shots to
work from, and then throw the rest away. Though it sounds like youve wasted
good work, there is no doubt that trying to retro-fit into an existing prototype can
often consume more time than building an application from scratch.
Page 23
As you build more applications and your templates and code toolkits become of
higher quality, you may find that it finally becomes feasible to prototype re-using
those established objects, and you will end up with a kernel of the new system at
the end of the process.
CONCLUSION
Page 24