Oracle Forms Coding Standards 20 Best Practices for Clean, Maintainable Forms

Oracle Forms Coding Standards: 20 Best Practices for Clean, Maintainable Forms

Why Coding Standards Matter More Than Ever

Let me be direct about something uncomfortable: most Oracle Forms applications in production today are maintained by people who did not write them. The original developer moved on. The documentation is sparse. The code works—until it doesn’t—and then someone has to figure out what a trigger named WHEN_BTN_3 actually does.

This is not a technology problem. Oracle Forms is fully capable of supporting clean, professional code. The problem is that many teams never established—or enforced—coding standards.

The irony is that Oracle itself has published detailed coding standards for Forms development for decades . These standards were created for the Oracle E-Business Suite, but the principles apply to any serious Forms project. The search results for this topic reveal a consistent set of recommendations that experienced Forms developers have converged on: centralize logic in packages, use handlers instead of trigger code, avoid direct built-in calls in favor of wrapped versions, and maintain consistent naming throughout .

This article distills those principles into 20 practical coding standards you can adopt today. Each standard includes the rationale, the pattern, and the anti-pattern to avoid.

The Foundation: Structure Your Code Like a Professional

1. Use the Template Form for Every New Development

Oracle’s own standards are unambiguous: all new Forms development should begin by copying the TEMPLATE form, which includes references to standard libraries, required triggers, and property classes .

Why it matters: The TEMPLATE form (and its Oracle E-Business Suite counterpart, APPSTAND) provides a foundation that enforces consistency from the first moment. It includes object groups for toolbars, calendars, and find windows. It attaches the standard libraries that provide core functionality. Starting from a blank form means you will manually recreate all of this—or worse, forget to include it .

The pattern: Copy TEMPLATE.fmb, rename it (including the internal module name and the FND_STANDARD.FORM_INFO call in PRE-FORM), and begin your development .

The anti-pattern: Opening Forms Builder, clicking “New Form,” and building from scratch. Every form built this way will be slightly different from every other form in the application.

2. Centralize Logic in PL/SQL Packages, Not Triggers

This is the single most impactful standard on this list. Oracle’s guidance is explicit: most code should reside in procedures within packages, and trigger code should be minimal .

Why it matters: A trigger with 50 lines of validation logic is invisible until you open that specific item in that specific block. A package procedure with 50 lines of validation logic is visible in the form’s Program Units section, searchable, and reusable. When the validation rule changes, you update one procedure—not fifteen triggers scattered across the form .

The pattern: Create a package for each block. Name it after the block (e.g., EMP package for the EMP block). Add procedures for each item handler, event handler, and table handler. Call these procedures from thin triggers .

The anti-pattern:

plsql

— BAD: Everything in the trigger

WHEN-VALIDATE-ITEM

BEGIN

IF :EMP.SALARY < 0 THEN

MESSAGE(‘Salary cannot be negative.’);

RAISE FORM_TRIGGER_FAILURE;

END IF;

IF :EMP.SALARY > 50000 THEN

MESSAGE(‘Salary exceeds maximum.’);

RAISE FORM_TRIGGER_FAILURE;

END IF;

— … 40 more lines

END;

The good pattern:

plsql

— GOOD: Trigger calls a handler

WHEN-VALIDATE-ITEM

BEGIN

EMP.VALIDATE_SALARY;

END;

— In the EMP package

PROCEDURE VALIDATE_SALARY IS

BEGIN

IF NAME_IN(‘EMP.SALARY’) < 0 THEN

MESSAGE(‘Salary cannot be negative.’);

RAISE FORM_TRIGGER_FAILURE;

END IF;

IF NAME_IN(‘EMP.SALARY’) > 50000 THEN

MESSAGE(‘Salary exceeds maximum.’);

RAISE FORM_TRIGGER_FAILURE;

END IF;

END VALIDATE_SALARY;

3. Use Item Handlers for Item-Specific Logic

An item handler is a procedure that contains all the logic for validating a particular item . Oracle’s standards recommend naming these procedures after the item they handle.

Why it matters: When you need to understand how EMP.SALARY is validated, you look in the EMP package for a procedure named VALIDATE_SALARY or SALARY. You do not hunt through triggers. When the validation changes, you update one procedure .

The pattern: For an item named SALARY, create PROCEDURE SALARY in the block’s package. The WHEN-VALIDATE-ITEM trigger calls EMP.SALARY.

The naming convention: Oracle’s standard is to name the procedure after the item, using the same name. The trigger distinguishes which event fired .

4. Use Event Handlers for Cross-Item Logic

Not all logic belongs to a single item. Event handlers encapsulate logic that spans multiple items or responds to block-level and form-level events .

Why it matters: A POST_QUERY handler that populates five non-base-table items belongs in one place, not scattered across five item handlers. An event handler makes this logic visible and maintainable .

The pattern: Name event handlers after the trigger they replace, with underscores instead of hyphens. POST-QUERY becomes POST_QUERY. WHEN-CREATE-RECORD becomes WHEN_CREATE_RECORD .

Common event handlers include:

  • PRE_QUERY — Populate query criteria
  • POST_QUERY — Populate non-base-table items
  • WHEN_CREATE_RECORD — Set complex defaults
  • WHEN_VALIDATE_RECORD — Validate inter-item relationships

5. Use Table Handlers for Database Interaction

Image

When a block is based on a view, Forms cannot automatically perform INSERT, UPDATE, DELETE, or LOCK operations. You must provide this logic yourself. Oracle’s standards call these table handlers .

Why it matters: A table handler encapsulates all database interaction for a block in one place. When the underlying table structure changes, you update the table handler—not a dozen ON-INSERT, ON-UPDATE, and ON-DELETE triggers scattered throughout the form.

The standard procedures in a table handler are:

  • CHECK_UNIQUE — Verify unique constraints
  • CHECK_REFERENCES — Verify referential integrity
  • INSERT_ROW — Handle inserts
  • UPDATE_ROW — Handle updates
  • DELETE_ROW — Handle deletes
  • LOCK_ROW — Handle row locking

The pattern: For a block based on the EMP table, create an EMP package with these procedures. The ON-INSERT trigger calls EMP.INSERT_ROW, the ON-LOCK trigger calls EMP.LOCK_ROW, and so on.

Naming and Readability: The Foundation of Maintainability

6. Follow Consistent Naming Conventions for Triggers

Oracle Forms has two types of triggers: standard triggers (built-in, like WHEN-BUTTON-PRESSED) and user-defined triggers (created by you). The naming convention distinguishes them .

The rule: Standard triggers use hyphens. User-defined triggers use underscores or no separator. This is a visual clue about what you are looking at .

Why it matters: When you see SHOW_HELP_CONTENTS, you know it is user-defined and must be called explicitly. When you see WHEN-BUTTON-PRESSED, you know it fires automatically.

The anti-pattern: Creating a user-defined trigger named WHEN-SHOW-HELP. The hyphens suggest it is a standard trigger, which causes confusion.

7. Name Blocks After Their Data Source

Oracle’s guidance is straightforward: block names should be the name of the table or view that is the main source of data .

Why it matters: A block named BLK1 tells you nothing. A block named EMPLOYEES tells you exactly what data it contains. When you are debugging a form with fifteen blocks, this matters enormously .

The pattern: If your block is based on the EMPLOYEES table, name it EMPLOYEES. If it is a control block containing buttons, name it by function: TOOLBAR, CONTROL, etc. .

The anti-pattern: BLOCK1, DATA_BLOCK, MAIN_BLOCK. These names provide no semantic information.

8. Name Items After Their Database Columns

The same principle applies to items. Item names should match the database columns they represent .

Why it matters: When you see :EMPLOYEES.SALARY, you know immediately which column this data comes from. When you see :EMPLOYEES.FIELD_17, you have to look up the item’s property sheet to understand what it contains .

The exception: Control items (buttons, display items, non-database items) should be named by function: BTN_SAVE, DSP_TOTAL, CHK_ACTIVE.

9. Use Consistent PL/SQL Formatting

Oracle’s standards include specific formatting guidelines for PL/SQL code :

  • Indent by two spaces. Not four, not a tab. Two spaces makes nested logic visible without excessive horizontal scrolling.
  • Indent SQL statements consistently. The SELECT, FROM, and WHERE clauses should be aligned for readability.
  • Use uppercase for reserved words, lowercase for identifiers. PL/SQL is case-insensitive, but consistent casing improves readability .
  • End procedures with the procedure name. END CHECK_SALARY; not just END;. This makes it easier to identify which procedure is ending in a long package .

The anti-pattern: Inconsistent indentation, mixed case, and bare END; statements. This code is technically correct but professionally sloppy.

10. Avoid Deeply Nested IF-THEN-ELSE

Oracle’s standards explicitly call this out: use IF-THEN-ELSIF instead of nested IF-THEN-ELSE .

Why it matters: Deeply nested IF blocks are hard to read and hard to debug. A 5-level nesting is a maintenance nightmare.

The anti-pattern:

plsql

IF condition1 THEN

IF condition2 THEN

IF condition3 THEN

IF condition4 THEN

— Logic here

END IF;

END IF;

END IF;

END IF;

The good pattern:

plsql

IF condition1 THEN

— Logic

ELSIF condition2 THEN

— Logic

ELSIF condition3 THEN

— Logic

ELSIF condition4 THEN

— Logic

END IF;

Built-in Usage: The Professional Approach

11. Use DO_KEY Instead of Direct Built-in Calls

Oracle’s standards are emphatic about this: routinely use DO_KEY instead of calling built-ins directly .

Why it matters: When you call COMMIT_FORM directly, you bypass any logic in the KEY-COMMIT trigger. When you call DO_KEY(‘COMMIT_FORM’), the trigger fires normally, and any custom logic you have added runs .

The pattern: Replace COMMIT_FORM with DO_KEY(‘COMMIT_FORM’). Replace EXIT_FORM with DO_KEY(‘EXIT_FORM’). Replace CLEAR_FORM with DO_KEY(‘CLEAR_FORM’) .

The exception: If you specifically need to avoid the trigger logic (rare), call the built-in directly.

12. Avoid CALL_FORM in E-Business Suite (Use FND_FUNCTION.EXECUTE)

If you are developing for Oracle E-Business Suite, CALL_FORM is incompatible with the standard navigation routines. Oracle’s standards require using FND_FUNCTION.EXECUTE instead .

Why it matters: FND_FUNCTION.EXECUTE respects EBS security, finds the correct form path, and integrates properly with the application’s session management. CALL_FORM bypasses all of this .

The pattern: Replace every CALL_FORM and OPEN_FORM call with FND_FUNCTION.EXECUTE .

13. Use OPEN_FORM Instead of NEW_FORM for Navigation

Oracle’s performance guidance includes a specific recommendation: use OPEN_FORM instead of NEW_FORM when navigating between forms .

Why it matters: NEW_FORM closes the current form before opening the new one. OPEN_FORM keeps the current form open. Closing and reopening forms involves significant overhead .

The pattern: For frequently-used forms, navigate with OPEN_FORM. The form remains in memory, and navigation back to it is instant.

14. Handle WHEN-CREATE-RECORD with Insert-Allowed Check

The WHEN-CREATE-RECORD trigger fires even when a block does not allow inserts. Oracle’s standards include a defensive check .

The pattern:

plsql

WHEN-CREATE-RECORD

BEGIN

IF GET_ITEM_PROPERTY(‘BLOCK_NAME’, INSERT_ALLOWED) = ‘FALSE’ THEN

NULL;

ELSE

— Your default-setting logic here

END IF;

END;

Why it matters: Without this check, your default-setting logic may run in query-only mode, causing unexpected behavior.

Exception Handling: Professional Error Management

15. Use RAISE FORM_TRIGGER_FAILURE, Not RAISE_APPLICATION_ERROR

Image

Oracle’s standards are explicit: do not use RAISE_APPLICATION_ERROR in Forms code .

Why it matters: RAISE_APPLICATION_ERROR conflicts with the exception-handling scheme used by Oracle Forms and the E-Business Suite. Use RAISE FORM_TRIGGER_FAILURE to stop processing instead .

The pattern:

plsql

IF error_condition THEN

FND_MESSAGE.SET_NAME(‘APP’, ‘MESSAGE_NAME’);

FND_MESSAGE.ERROR;

RAISE FORM_TRIGGER_FAILURE;

END IF;

Critical note: RAISE FORM_TRIGGER_FAILURE stops processing quietly—it does not display an error by itself. You must display your message before raising the exception .

16. Write Explicit Exception Handlers

Oracle’s SQL standards include a clear rule: write exception handlers for NO_DATA_FOUND instead of coding COUNT statements .

Why it matters: A SELECT COUNT(*) to check for existence is two round-trips to the database. A SELECT INTO with a NO_DATA_FOUND handler is one.

The pattern:

plsql

BEGIN

SELECT column INTO variable

FROM table

WHERE condition;

EXCEPTION

WHEN NO_DATA_FOUND THEN

— Handle the no-data case

NULL;

END;

The anti-pattern:

plsql

SELECT COUNT(*) INTO counter FROM table WHERE condition;

IF counter > 0 THEN

SELECT column INTO variable FROM table WHERE condition;

END IF;

Libraries and Reusability: Building for the Future

17. Put Generic Code in Libraries, Keep Form-Specific Code in the Form

Oracle’s guidance on PL/SQL libraries is balanced: generic code should go into libraries, and code unique to each form should stay there .

Why it matters: Putting everything into libraries creates a different maintenance problem—over-coupled code that is hard to change. The goal is reusable code, not maximally shared code .

The pattern:

  • Libraries: String utilities, date calculations, common validations, UI helpers
  • Form: Block-specific validation, item-specific logic, form-specific workflows

The library advantage: Code in libraries cannot reference form objects directly. This forces parameterization, which makes the code inherently more reusable .

18. Prefer Parameterization Over NAME_IN/COPY Indirection

Image

When writing library code, you have two choices for accessing form values: indirection (NAME_IN, COPY) or parameterization (passing values as arguments). Oracle’s guidance is clear: use parameters whenever possible .

Why it matters: NAME_IN(‘EMP.SALARY’) contains a hardcoded reference. It can only work in forms that have an item named EMP.SALARY. A procedure that accepts p_salary NUMBER works in any form .

Performance bonus: Parameterized procedures are faster at runtime because there is no indirect lookup .

The pattern:

plsql

— GOOD: Parameterized

PROCEDURE CHECK_RANGE(p_value IN NUMBER, p_min IN NUMBER, p_max IN NUMBER);

— ACCEPTABLE: Indirection when necessary

PROCEDURE CHECK_ITEM_RANGE(p_item_name IN VARCHAR2);

19. Use Package Variables Instead of Global Variables

Oracle’s performance guidance includes a specific recommendation: use package variables instead of Forms global variables .

Why it matters: Global variables consume 255 bytes each and have sizing and datatype translation issues. Package variables can be typed, are scoped to the package, and can be shared across forms through a library .

The pattern: Create a GLOBAL_DATA package in a shared library with typed package variables for cross-form data.

The exception: Global variables are sometimes necessary for passing data to Reports or for inter-form communication in older architectures.

20. Erase Global Variables When No Longer Needed

Image

If you must use Forms global variables, Oracle’s performance standards include this rule: erase globals when they are no longer required .

Why it matters: Each global consumes 255 bytes. An application that creates dozens of globals and never erases them has a memory leak that compounds over the user’s session.

The pattern:

plsql

— When done with a global

ERASE(‘GLOBAL.TEMP_DATA’);

Quick Reference: The 20 Standards at a Glance

# Standard Key Benefit
1 Start from TEMPLATE form Consistency from day one
2 Centralize logic in packages Maintainability reusability
3 Use item handlers Locate validation logic easily
4 Use event handlers Centralize cross-item logic
5 Use table handlers Isolate database interaction
6 Hyphens for standard triggers underscores for user-defined Visual clarity
7 Name blocks after data source Self-documenting code
8 Name items after columns Self-documenting code
9 Consistent PL/SQL formatting Readability
10 Avoid nested IF-ELSE Readability
11 Use DO_KEY Preserves trigger logic
12 FND_FUNCTION.EXECUTE in EBS Security path resolution
13 OPEN_FORM over NEW_FORM Performance
14 WHEN-CREATE-RECORD insert check Prevents unexpected behavior
15 RAISE FORM_TRIGGER_FAILURE Proper exception handling
16 Explicit NO_DATA_FOUND handlers Performance clarity
17 Libraries for generic forms for specific Balanced reusability
18 Parameterize over NAME_IN/COPY Reusability performance
19 Package variables over globals Memory type safety
20 Erase globals when done Prevent memory leaks

The Cultural Challenge: Standards Are Worthless Without Enforcement

Here is the uncomfortable truth: you can write the most comprehensive coding standards document in the world, and it will mean nothing if the team does not follow it.

Oracle’s own standards were enforced through a combination of template forms, shared libraries, and code review. The TEMPLATE form makes it easier to follow the standards than to deviate from them. The shared libraries provide the functionality, so there is no incentive to reinvent it .

Practical enforcement mechanisms:

Code reviews. Every form gets reviewed by another developer before it is promoted. The review checklist includes the standards in this article.

Templates. Make the TEMPLATE form the only starting point. Remove the temptation to start from scratch.

Libraries. Provide the utility functions so developers do not write their own. The path of least resistance should be the compliant path.

Automated checks. Where possible, use scripting to detect violations (e.g., missing exception handlers, overly long triggers).

Lead by example. If the senior developers violate the standards, no one will follow them. If the senior developers consistently write clean code, the rest of the team will emulate them.

Conclusion: Clean Code Is a Choice, Not an Accident

Oracle Forms applications can be as clean, maintainable, and professional as any modern codebase. The tools and standards have existed for decades . The question is whether development teams choose to use them.

The 20 standards in this article represent the consensus of Oracle’s official guidance and the collective experience of the Forms development community. They are not theoretical. They are battle-tested practices that reduce defects, speed up maintenance, and make life easier for every developer who touches the code after you.

Adopt them. Enforce them. And the next developer who opens your forms will thank you

Previous