Naming Conventions and Coding Standards
Naming Conventions and Coding Standards
Author: Steven Feuerstein, [email protected] Copyright: Steven Feuerstein, 2009. All rights reserved. Downloadable from: http://www.ToadWorld.com/SF/standards
Modification History
Date May 27, 2009 Mid-May 2009 May 17, 2009 Change Publish on ToadWorld Incorporate recommendations from John Beresniewicz and Patrick Barel Document distributed for review By Steven Feuerstein Steven Feuerstein Steven Feuerstein
Contents
Introduction ......................................................................................................................... 1 Principles Underlying My Standards .................................................................................. 3 Table of Naming Conventions ............................................................................................ 4 General Guidelines I Try to Follow .................................................................................... 6 Naming Conventions I Reject ............................................................................................. 8 How to Verify Naming Conventions and Standards........................................................... 9 PL/Scope Examples ........................................................................................................ 9 Things I still wonder about ............................................................................................... 12
Introduction
I am often asked about the naming conventions and coding standards that I use. My answer is usually a combination of muttering and vague statements and hand-waving. That's because I have a confession: I don't have a single naming conventions and coding standards document that I use. Why not? Because I am a software developer! That is, I feel (well, I am) very busy, overwhelmed by deadlines. I don't feel like I have the time to stop and write down the few rules that I might actually follow more of less consistently. And it seems that a part of me is somewhat resistant to being accountable to a standard. Sound familiar? Sigh...unfortunately (no, make that very fortunately), lots of other PL/SQL developers look to me for advice about how to "do things right." Ah, the pressure, the pressure!
Page 1 |
Ah, the hypocrisy. That's what it really comes down to: I am a big hypocrite. I routinely violate just about every best practice I push on others. I sound high and mighty, but when I write code, I feel the same pull to do the quick and dirty. Yet, I do have standards, and I even follow them, more or less. It's just been hard to find the time to write them down. So that's (finally) what you'll find below. It's a combination of the naming conventions I follow, certain naming conventions with which I disagree, and a variety of other suggestions. I hope you find it useful. I'm not going to make much of an effort to justify my approach or explain away the inconsistencies. I'll just show you what I do and you can decide if you'd like to use my path as a model for your own journey. This is a work in progress. If you have disagreements with my approach, have a suggestion for something to add to this document, or would like to offer your own set of naming conventions and coding standards to the world of PL/SQL, send me a note at [email protected] or [email protected]. If I agree with it, I will put it into the document (and give you credit!) or make it available on the web page on which this document is located: http://www.ToadWorld.com/SF/standards
Page 2 |
Page 3 |
Type of element Variable declared in a PL/SQL block (anonymous, nested, subprogram) Constant declared in a PL/SQL block (anonymous, nested, subprogram) Variable declared at the package level Constant declared at the package level Explicit cursor
c_<rootname>
c_max_salary
[SC_]<rootname>_cv [SC_]<rootname>_rt Same as local or global variable, singular form. Sometimes I used a prefix like "_info" to indicate its a bunch of information, not just a single value.
Collection types
Collection variable
l_employees Page 4 |
variable, plural form Object type [SC_]<rootname>_ot or [SC_]<rootname>t IN parameter <rootname>_in or <rootname>_i OUT parameter <rootname>_out or <rootname>_o IN OUT parameter <rootname>_inout or <rootname>_io That's a bit verbose, I know. salary_inout salary_out salary_in employee_ot
Page 5 |
But the code will be hard to understand. Declare distinct variables, exceptions, etc. so that the names are specific and relevant to the task at hand. Most definitely do not do what Oracle did with NO_DATA_FOUND: raise it for a SELECT INTO that returns no rows, an attempt to read an element in a collection at an index value that is undefined, an attempt to read past the end of a file. How silly! I try to avoid repeating variable names at different scopes (especially nested and especially parameters): this can easily and often happen with cut and paste, and procedure extraction. It is, I suppose, a violation of my "Don't Recycle" rule, but it's more of an accidental repurposing. The problem with having the same name used for multiple, nested levels is that unless you qualify each reference (which is not a common practice), you can easily end up referencing the "wrong" variable or parameter. Qualify all column names and variables names inside SQL statements in PL/SQL. This is valuable not only for making the code more readable and guarding against really hard to pin down bugs (when, for example, the DBA adds a new column to the table called "employee_id_in," which just so happens to match the naming convention you use for parameters), but also to take advantage of Oracle Database 11g's fine-grained dependency feature to minimize the invalidation of program units when referenced objects are changed. Add labels to the END statements of all your packages, procedures, functions, etc. It is a small thing that greatly aids in readability. Rely on a single, generic error manager utility to raise, handle and log errors. Individual developers should never waste their time calling DBMS_UTILITY.FORMAT_ERROR_BACKTRACE (though you should definitely know what that is!) or writing inserts into log tables. You end with total Page 6 |
chaos and inconsistent information for both users and support. The best way to avoid this is to rely on a single utility. If you don't already have one, check out the freeware Quest Error Manager, currently available at http://www.ToadWorld.com (press Download button and then "Exclusive ToadWorld Downloads). Stop writing so much SQL! Every SQL statement is a hard-coding of the current data structures. Don't repeat the same logical SQL statement. Keep SQL out of application-level code entirely. Instead, generate/build and rely on APIs (tablelevel, transaction-level) that hide SQL statements behind procedures and functions. One way to accomplish this: download the Quest CodeGen Utility from ToadWorld.com (press Download button and then "Exclusive ToadWorld Downloads). CodeGen generates API packages for you and it's free! Write tiny, little chunks of code (). Use top-down design, combined with reusable code and local subprograms (procedures and functions declared within another procedure or function), to make sure that your executable sections have no more than 50 lines of code in them. Define your subprograms at the package level if they need to be used by more than one program in that package or outside of that package.
Page 7 |
Page 8 |
PL/Scope Examples
1. Enable gathering of PL/Scope information:
ALTER SESSION SET plscope_settings='IDENTIFIERS:ALL' /
3. Finally, to show you what really is possible with PL/Scope, I offer a query to validate the following naming convention violations (and, yes, I realize that they do not match mine): Type definitions should be named starting with t_ Names of global (package level) variables should start with g_ Parameters are named p_<parameter description> Local variables have names starting with l_ Page 9 |
Variable and parameter names should be written in lowercase No variables should be declared in the package specification This was written by Lucas Jellema of the AMIS consulting firm. His complete explanation is available on AMIS's fantastic blog:
http://technology.amis.nl/blog/2584/enforcing-plsql-naming-conventionsthrough-a-simple-sql-query-using-oracle-11g-plscope WITH identifiers AS (SELECT , , , , , , FROM i.name i.TYPE i.usage s.line i.object_type i.object_name s.text source user_identifiers i JOIN user_source s ON ( s.name = i.object_name AND s.TYPE = i.object_type AND s.line = i.line) WHERE object_name = '&1'), global_section AS ( SELECT MIN (line) end_line, object_name FROM identifiers WHERE object_type = 'PACKAGE BODY' AND TYPE IN ('PROCEDURE', 'FUNCTION') GROUP BY object_name), naming_convention_violations AS (SELECT name identifier , 'line ' || line || ': ' || source sourceline , CASE WHEN TYPE = 'RECORD' AND usage = 'DECLARATION' AND SUBSTR (LOWER (name), 1, 2) <> 't_' THEN 'Violated convention that type definitions should be called t_<name>' WHEN TYPE IN ('FORMAL IN', 'FORMAL IN OUT', 'FORMAL OUT') AND usage = 'DECLARATION' AND SUBSTR (LOWER (name), 1, 2) <> 'p_' THEN 'Violated convention that (input and output) parameters should be called p_<name>' WHEN TYPE = 'VARIABLE' AND usage = 'DECLARATION' THEN CASE WHEN line < global_section.end_line /* global variable */ AND SUBSTR (LOWER (name), 1, 2) <> 'g_' THEN 'Violated convention that global variables should be called g_<name>' WHEN line > global_section.end_line /* local variable */ AND SUBSTR (LOWER (name), 1, 2) <> 'l_' THEN
Page 10 |
'Violated convention that local variables should be called l_<name>' END END MESSAGE FROM identifiers JOIN global_section USING (object_name)), global_violations AS (SELECT name identifier , 'line ' || line || ': ' || source sourceline , CASE WHEN TYPE = 'VARIABLE' AND usage = 'DECLARATION' AND object_type = 'PACKAGE' THEN 'Violated convention that there should not be any Global Variables in a Package Specification' END MESSAGE FROM identifiers), casing_violations AS (SELECT name identifier , 'line ' || line || ': ' || source sourceline , CASE WHEN TYPE = 'VARIABLE' AND usage = 'DECLARATION' AND INSTR (source, LOWER (name)) = 0 THEN 'Violated convention that variable names should spelled in lowercase only' END MESSAGE FROM identifiers), convention_violations AS (SELECT * FROM naming_convention_violations UNION ALL SELECT * FROM global_violations UNION ALL SELECT * FROM casing_violations) SELECT * FROM convention_violations WHERE MESSAGE IS NOT NULL /
Page 11 |
Page 12 |