Thursday 8 September 2011

Bryn Llewellyn's Thoughts on Standards

Bryn Llewellyn, PL/SQL Product Manager, reviews each of my answers on OTN. Over the years, we have often come back to this topic of standards. We both recognize that it's impractical to have set of rigid rules to apply to every conceivable situation; it's important to stay focused on the ends, rather than the means, when it comes to standards: How do we make our code more readable and maintainable?
After reading my answer in the previous section, Bryn offered the following perspectives on coding standards and kindly agreed to let me share them with you.
Here's what Bryn likes (in no particular order):
• Use lower case for key- and reserved words.
• Use underscores to separate individual "words" in an identifier, and use "init cap" for each word, as in Maximum_Allowed_Error. The underscores are important for readability in error messages and simila,r where everything is (sadly) upper cased for display.
• Use all capital letters when the sequence of letters is itself an abbreviation—as is Data Base Management System: DBMS_Output.Put_Line. Of course, we should recognize that the rule won't always work (Utl_File or UTL_File?). It's a contraction and not an abbreviation, but how concerned should we get about such things?
• Allow a single lower case "j" and similar.
• Use nested declare-begin-end blocks to allow short names like "j" without the need for a comment-long essay and to avoid the risk of re-use error.
• declare j:= Things.First();
• begin
• while j is not null loop
• Name a procedure with an imperative (phrase), as in Calculate_Totals.
• Name a function and a variable with a noun (phrase), as in Total_Sales.
• Name an exception to describe a state of affairs (No_Data_Found).
• Use a _t suffix for a type name.
• Use a plural name for a collection (Things Things_t).
• Use subtypes a lot: Subtype Idx_t is pls_integer.
• Don't hestitate to compress a compound statement onto a single line if it fits, as in:
• if Total < 1 then raise Total_Is_Negative; end if;
• The same rules should apply to an identifier, whether it names a variable, subprogram, type name, exception, or whatever.
• Indent only two spaces. It's sufficient, and horizontal space is at a premium.
• Use $if $$false $then ... $end (the new conditional compilation feature available in Oracle Database 10g Release 2) to "comment out" code while developing.
• Avoid double-quoted identifiers such as "$my silly *?! name"
• Use end labels ("end Do_My_Thing;") at the end of a subprogram and other compilation unit.
• Consider using the end label for loops, if compound statements, inner blocks, etc., and label the start of the compound statement, as in:
• <<Searching>loop
• ...
• end loop Searching;
(Note that the compiler doesn't yet check that the names match.)
• Avoid trailing comments and especially /* */ embedded comments on lines with code.
• Use only dash-dash (single line) comments. The comment should precede the code it describes.
• When you invoke a subprogram with no actual arguments, always use trailing empty parentheses: Do_It(). This clearly distinguishes the fact that the identifier represents a subprogram rather than a variable.
• Examine every local variable use to determine if you can declare it as a constant. This will help later maintainers and can help the optimizer. It can never be harmful.
Bryn also thinks that it's instructive to look at the following notorious example (it is not exactly orthography—but it sometimes leads to it):
create table Things(pk number primary key, n number)
/
create procedure P(n in Things.n%type) is
begin
-- We presume that no-one wants to select all rows!
<<Select_From_Things>>for Thing in (select pk from Things where n = n) loop
...
end loop Select_From_Things;
end P;
/
There are two ways to resolve the problem:
select pk from things where n = i_n
and
select pk from things where n = P.n
Bryn thinks that it's far more important to understand the issue than it is always slavishly to follow a prefix/suffix convention. After all, it might be defeated—or made to look silly—if the column names unfortunately use the same decoration for a different reason. Having said that, I do understand that in the real world you have to deal with large teams of programmers where some are less clear thinking than others! So in some cases, you do need slavish rules.
You can see applications of these rules in the code examples found in the Oracle Technical White Paper on conditional compilation.
I like lots of Bryn's ideas, but we differ on one important guideline: Bryn prefers to put all key- and reserved words in lower case, while I prefer upper-case. I like to make the keywords stand out, and to put some variation into the code. I find it easier to read. Bryn, on the other hand, has this to say about case and keywords:
"Avoid UPPER CASE KEYWORDS. Doing that makes PL/SQL look so old-fashioned! And it calls out the wrong things. After all, such words in C—which is case-sensitive—are lower case, yes? Why did they pick that rule rather than upper case? UPPER CASE is also harder to read—as research on road signs has shown.
"Let's assume that the aim is to distinguish clearly between keywords and identifiers. Well, the following rules certainly achieve the goal:
• All key- and reserved words in lower case.
• With the exception of single-character ones, identifiers should have at least one capital letter.
Don't fuss too much about things like "Dual" or "Nextval" (or "NextVal"). These are identifiers (not keywords) to which Oracle has given special significance. I tend to treat them like identifiers. Others might prefer to treat them like keywords. But I have to say that treating, say, DBMS_Output.Put_Line as if it were a keyword seems a bit silly."

1 comment: