Directives

[Previous] [ Next ]

9.1 Document the purpose of the code.

It's not enough just to add comments to a procedure; you need to write good comments. Comments that simply reiterate what the code does add almost nothing to the code. In fact, if you're using good naming techniques to create self-documenting code, these types of comments add absolutely nothing. For instance, look at the comment in the following procedure. It simply reiterates the code itself; the variable names are even used within the comment. This comment documents the mechanics of the code rather than the purpose of the code or the reasoning behind it.

  PrivateSub  cmdStartSale_Click()  Dim  intAge  AsInteger   Const  c_LegalAge=21 intAge=txtAge.Text  '*IfintAge>=c_LegalAgethenprocessthesale.   If  intAge>=c_LegalAge  Then   Call  ProcessSale  EndIf EndSub  

When you find yourself writing a comment that includes the literal name of a variable, stop and rethink the comment. Unless you're documenting the variable itself or reminding the reader of the purpose of an obscure variable, you should refrain from using variable names directly within a comment. When a variable name is used in a comment, the comment probably reiterates the code. Instead, you should document the purpose of the code or the reasoning behind it. The following procedure is identical to the previous one, but in this case the comment correctly annotates the code:

  PrivateSub  cmdStartSale_Click()  Dim  intAge  AsInteger   Const  c_LegalAge=21 intAge=txtAge.Text  '*Ifthebuyerisoflegalagetopurchasealcohol,   '*processthesale.   If  intAge>=c_LegalAge  Then  CallProcessSale  EndIf EndSub  
NOTE
Comments should describe the purpose of a section of code, not the mechanics of how it accomplishes that purpose ”the why rather than the how.

9.2 If you need to violate good programming style, explain why.

At times it might be necessary to violate good coding principles. When you encounter such a situation, document what you are doing and why, using an inline comment. For instance, say you are unable to write your own sort routine or are under severe time constraints ( laziness doesn't count), so you use a hidden list box control to sort a set of values. You place the list box on a form and set its Sorted property to True and its Visible property to False. You then populate the list box with all the elements to sort using the list box's AddItem method. Finally, you retrieve the newly sorted values from the list by using a loop to reference the list box's List property. This is clearly a hack, but it works. In cases such as this, it is imperative that you document what you are doing and why. The following code shows how you might document such a process.

  '*AddthenamesinthenamearraytothelstSort   '*listbox.IthasitsSortedpropertysettoTrue,   '*soloopingthroughthelistitemswillreturn   '*thevaluesinthearrayinsortedorder.   For  intIndex=1  ToUBound  (a_strNames) lstSort.AddItema_strNames(intIndex)  Next  intIndex 

9.3 Document when an error is expected and why.

Due to the nature of Microsoft Visual Basic, some errors are unavoidable and others are absolutely necessary. For instance, you might decide that rather than attempting to see whether a record exists in a database before trying to save a new record (to avoid creating duplicates) it would be quicker to attempt to save the record and trap the error if the record is a duplicate. The following code shows this situation. When you expect an error in code and you deliberately trap for it, fully document why you're trapping the error and what error you expect. If more than one error might occur, document the others as well. (See Chapter 7, "Error Handling," for more information on trapping errors.)

  '*Traptheerrorincasetheuserisattemptingtosavea   '*duplicaterecord.   OnErrorResumeNext  Err.Clear dbSales.ExecutestrSQL,dbFailOnError  Const  c_DuplicateRecord=3022  '*Ifanerroroccurred,determinewhetheritwasbecauseof   '*tryingtosaveaduplicaterecord.   If  Err.Number<>0  Then   '*Seewhethertheerrorwasexpected.   If  Err.Number=c_DuplicateRecord  Then   '*Theuserattemptedtosaveaduplicaterecord.   '*Telltheuserandgetout.  MsgBox"Theitem'"&txtItem.Text&"'alreadyexists"&_ "inthedatabase.",vbInformation  GoTo  PROC_EXIT  Else   '*Thisisanunexpectederror;notifytheuser.   Call  ShowError(Me.Name,"ChangeCode",Err.Number,_   Err.Description)  GoTo  PROC_EXIT  EndIf EndIf   '*Turnregularerrortrappingbackon.   OnErrorGoTo  PROC_ERR 

Sometimes, a statement might cause an error that is always benign . This can happen with Visual Basic's venerable SetFocus method. This method, which places the cursor into a specific control, has many applications. For example, you can use SetFocus when the user switches among tabs in a dialog box to ensure that when a new tab is displayed the first control on the tab has the focus. You can also use SetFocus when you validate data to put the cursor in a text box with invalid data so that the user can quickly correct the problem. While SetFocus is used liberally in most applications, many developers fail to precede each call with On Error Resume Next . You should do this because if a form or a parent control hasn't fully painted itself, SetFocus might fail with an Error 5. This error doesn't hurt anything, and in most cases it's perfectly acceptable to ignore the error. Since this particular situation happens frequently, it's probably not advisable to document each occurrence, but when you do want to document it you can use a comment such as the one shown here:

  '*Ignoreanyerrorsthatoccurbecausetheformisnotreadyforthe   '*controltoreceivethefocus.   OnErrorResumeNext  txtName.SetFocus  '*Turnregularerrortrappingbackon.   OnErrorGoTo  PROC_ERR 

9.4 Comment before writing code.

One approach to commenting code is to start a procedure by writing the comments first. You can write full sentence comments or pseudocode if you prefer. Once you outline the code with comments, you can write code between the comments. As you write the procedure, you might have to adjust your comments. After you write the procedure, convert all pseudocode comments to standard sentences. The following is a shell of a procedure that consists of comments only:

  PublicSub  FloodFill(X  AsSingle  ,Y  AsSingle  )  '*Purpose:Fillanareaonthebitmapwithacolor.   '*Accepts:XandY-coordinatesonthebitmapwhere   '*thefillshouldbegin.   '*SettheFillStyleofthepictureboxtosolidandthe   '*FillColortothecurrentdrawingcolor.   '*Gettheboundarycolorforthefill.Thisisthecurrentcolor   '*atthespecifiedcoordinates.   '*UsetheExtFloodFillAPIcalltoperformafastfloodfill,   '*changingalladjacentpixelsthathavetheboundarycolor   '*tothecurrentdrawingcolor.   EndSub  

The initial comments are like an outline. After you write them, you can fill in the outline with the necessary code. The following is the finished procedure with code inserted between the comments. The comments do not simply repeat the code; they explain what is occurring. In this example, the comments did not need to be changed or moved, but that won't always be the case.

  PublicSub  FloodFill(X  AsSingle  ,Y  AsSingle  )  '*Purpose:Fillanareaonthebitmapwithacolor.   '*Accepts:XandY-coordinatesonthebitmapwhere   '*thefillshouldbegin.   OnErrorGoTo  PROC_ERR  Dim  lngResult  AsLong   Dim  lngBoundaryColor  AsLong   '*SettheFillStyleofthepictureboxtosolidand   '*theFillColortothecurrentdrawingcolor.  picPreview.FillStyle=vbFSSolid picPreview.FillColor=m_lngDrawColor  '*Gettheboundarycolorforthefill.Thisisthecurrentcolor   '*atthespecifiedcoordinates.  lngBoundaryColor=picPreview.POINT(X,Y)  '*UsetheExtFloodFillAPIcalltoperformafastfloodfill,   '*changingalladjacentpixelsthathavetheboundarycolor   '*tothecurrentdrawingcolor.  lngResult=ExtFloodFill(picPreview.hdc,X,Y,_ m_lngBoundaryColor,FLOODFILLSURFACE) PROC_EXIT:  ExitSub  PROC_ERR: MsgBox"Error:"&Err.Number&vbCrLf&Err.Description  ResumeNext   EndSub  

9.5 Use solid-character comment lines only for major comments.

Some developers adopt formatting styles for comments that, while attractive, hinder the development process. It can be tempting to go overboard with comment formatting. A common example of such overzealousness is the use of formatting characters to create a line before or after comments. I call these comment lines solid-character comment lines . For instance, the asterisk (*) ”one of the most common formatting characters and my personal favorite ”is often overused in this way. Consider the comments in the following code fragment:

  '*******************************************************   '*Retrievethelengthsofthelegsoftherectangle.   '*******************************************************  sngXLeg=Abs(rectBound.Right-rectBound.Left) sngYLeg=Abs(rectBound.Bottom-rectBound.Top)  '*******************************************************   '*Makesuretherectangleisavalidrectangle.   '*******************************************************   If  (sngXLeg=0)  Or  (sngYLeg=0)  Then   '*******************************************************   '*Thisisnotavalidrectangle,sogetout.   '*******************************************************   GoTo  PROC_EXIT  EndIf   '*******************************************************   '*Populatethecirclestructurewiththedatathatdefines   '*thecircle.   '*******************************************************   With  udtCircle .Aspect=Abs(sngYLeg/sngXLeg) .xCenter=rectBound.Left+(rectBound.Right-rectBound.Left)/2 .yCenter=rectBound.Top+(rectBound.Bottom-rectBound.Top)/2  '*******************************************************   '*Determinetheradiususingthelongerlegoftherectangle.   '*******************************************************   If  sngXLeg>sngYLeg  Then  .Radius=sngXLeg/2  Else  .Radius=sngYLeg/2  EndIf   EndWith  

Wow ”all of those asterisks can give you a headache . If you leave your Visual Basic settings at their defaults, you'll see green all over the code window.

The color coding of comments is one of my favorite Visual Basic features. It seems so simple as to be almost silly, but if you've ever coded complex applications in Microsoft Access 2.0, which doesn't include a color-coded editor, you know where I'm coming from. I'd sooner quit developing than give up the color-coded editor. When scanning a procedure, it's great to be able to distinguish the comments in green text. But unnecessary comment lines decrease the ratio of usable green text to total green text.

In his book The Visual Display of Quantitative Information (Graphics Press, 1992), Edward Tufte discusses what he calls data ink, "the nonerasable core of a graphic." Nondata ink includes such elements as elaborate grid lines and detailed labels. Tufte discusses the necessity of a high data ink to total ink ratio. You can think of comments in much the same way.

Sometimes it makes sense to call attention to a comment by using solid-character comment lines, but in such cases they should be reserved for major comments, never minor comments. The solid-character comment lines in the following code are still overkill, but at least they make more sense by calling attention to the major elements of the procedure.

  '*******************************************************   '*Retrievethelengthsofthelegsoftherectangle.   '*******************************************************  sngXLeg=Abs(rectBound.Right-rectBound.Left) sngYLeg=Abs(rectBound.Bottom-rectBound.Top)  '*******************************************************   '*Makesuretherectangleisavalidrectangle.   '*******************************************************   If  (sngXLeg=0)  Or  (sngYLeg=0)  Then   '*Thisisnotavalidrectangle,sogetout.   GoTo  PROC_EXIT  EndIf   '*******************************************************   '*Populatethecirclestructurewiththedatathatdefines   '*thecircle.   '*******************************************************   With  udtCircle .Aspect=Abs(sngYLeg/sngXLeg) .xCenter=rectBound.Left+(rectBound.Right-rectBound.Left)/2 .yCenter=rectBound.Top+(rectBound.Bottom-rectBound.Top)/2  '*Determinetheradiususingthelongerlegoftherectangle.   If  sngXLeg>sngYLeg  Then  .Radius=sngXLeg/2  Else  .Radius=sngYLeg/2  EndIf   EndWith  

Solid-character comment lines pose additional problems. How many characters should the solid-character comment line contain? There's no doubt that they look better when they all contain the same number of characters, but what about when they're used before or after a short comment line? Or, more important, what about when they surround a longer comment, as they do in the previous example? Trying to maintain a consistent and attractive appearance with these solid-character comment lines quickly becomes tedious. Also, if you manually type each line, you're wasting time. The only alternatives to typing each line individually are to copy and paste the lines ”also tedious ”or to use some sort of code-formatting add-in.

9.6 Avoid creating comment boxes.

Far worse than solid-character comment lines are formatting characters on the right side of comments that create comment blocks or boxes. You've probably seen such comments, and you might have written a few. If you've ever maintained code that has these sorts of comments, chances are you've given up on them ”and for good reason. Take a look at this comment:

  '*************************************************************   '*Iftheuserclickstheleftbutton,getthecoloratthe*   '*currentcoordinatesandassignitastheForeColor.If*   '*therightbuttonhasbeenclicked,getthecolorunder*   '*thepointerandassignitastheBackColor.*   '*************************************************************  

Sure, the asterisks on the right look nice, but do they add anything to the comment? Actually, yes ”more work for the person writing or editing the comments. Notice the white space after the last word on the second line. As I was writing this comment, I typed the next word the, only to discover that it would run into the last asterisk. I was then faced with a decision and had to consider the following options:

  • Adding an additional asterisk to the first line (the header) and another space in front of the last asterisk on the second line to realign it with the header.
  • Backspacing over the word the, adding the necessary spaces and asterisk, and then resuming on the next line.
  • Moving the cursor in front of the word the, adding the necessary spaces and asterisk, and then pressing Enter to move the to the next line.

After I decided to put the word the on the next line and resume typing, I encountered the exact same problem ”oddly enough, with the exact same word. Isn't this fun? I added tedium to what many already call a tedious process. If writing comments was always this much work, I can see why some would choose to skip it altogether. Although the use of formatted lines in front of or after a comment can be justified to call attention to major events in code, the use of end-line formatting characters to create comment blocks is never justified. It does nothing but add extra work.

9.7 Use an apostrophe to denote comments.

In the old days of Basic, you denoted a comment by starting a line with the word REM (for Remark). Visual Basic still supports the use of REM , but you shouldn't use it. Using REM clutters the comment, creates wasted green space, necessitates more typing, can confuse add-in code formatters, and in general just looks bad. Instead of REM , use the apostrophe (') ”and, perhaps, as I do, an asterisk (*) ”to denote a comment:

  '*Ifthisisanewaccount,setupthenecessary   '*defaultinformation.Iftheaccountexists,place   '*therecordineditmode.   If  blnAddNew  Then    EndIf  

Practical Application

9.7.1 Use special characters to identify a comment's author or indicate its temporary status. In a multiple-developer environment, it's often desirable to know which developer wrote a specific comment. While you could store revision information in the procedure comment header, this is a cumbersome process and doesn't help when different developers work on different pieces of the same procedure.

A great solution to the problem of identifying a comment author is to assign a unique formatting character to each developer and to have the developer follow each remark character (') with his or her assigned formatting character. Once you get into the habit of doing this, it becomes second nature. This approach is useful only in departments with a small number of programmers. When you use a scheme like this, you should create a key of the users and their formatting characters in a global module. It might be a good idea to keep the authors' contact information there as well.

Correct:

  '*Purpose:Createtabstopsinalistbox.   '*Accepts:lstControl-thelistboxinwhichtosetthetabstops   '*lngTabs-thenumberoftabstopstoset   '*strStops-astringcontainingthecharacter   '*positionsofthetabstops   OnErrorGoTo  PROC_ERR 

Also correct:

  '$Purpose:Createtabstopsinalistbox. '$Accepts:lstControl-thelistboxinwhichtosetthetabstops '$lngTabs-thenumberoftabstopstoset '$strStops-astringcontainingthecharacter '$positionsofthetabstops   OnErrorGoTo  PROC_ERR 

You should also use a special character for temporary comments or notes. Temporary comments can be useful when you comment out a section of code while debugging or when you need to write more code later. In such cases, you should use a formatting character or a word to mark the comment as temporary. Use the comment designator consistently to make it easy to search a project for temporary comments. The character or word that you use is entirely up to you, but be sure that everyone working with the code uses the same format.

Correct:

  '#SECURITYSTILLNEEDSTOBEIMPLEMENTED!  strSQL="DELETE*FROMtblContacts;" dbContacts.ExecutestrSQL,dbFailOnError 

Also correct:

  'NOTE:SECURITYSTILLNEEDSTOBEIMPLEMENTED!  strSQL="DELETE*FROMtblContacts;" dbContacts.ExecutestrSQL,dbFailOnError 
NOTE
When you use formatting characters to denote something about a comment, document exactly what your standards are and share them with all developers.

9.8 Make your comments readable.

Comments are meant to be read by humans , not computers. Strive to make your comments intelligible. Keep in mind that a comment that is hard to understand is not much better than no comment at all. Also, as I've said throughout this chapter, comments are documentation. Just as documentation for an application must be clearly written, code comments should also follow good writing guidelines.

Practical Applications

9.8.1 Use complete sentences. While it's not necessary (and probably not advisable) to write paragraphs of comments, you should strive to write your comments in complete sentences. When developers write comments in phrases or sentence fragments , what they consider necessary information often falls short of what readers want or need to see. When you write comments in complete sentences, you force yourself to fully analyze the comment. Remember that excellent comments explain the general flow and purpose of a procedure even when stripped from the code they accompany.

Incorrect:

  '*Doesuserhaverights?   IfNot  (objApplication.Security.CanDeleteAccounts)  Then  MsgBox"Youdonothavesecurityrightstodeleteaccounts.",_ vbInformation  GoTo  PROC_EXIT  EndIf   '*Confirm   If  MsgBox("Deletethisaccount?",_ vbYesNo  Or  vbCritical)=vbNo  Then   GoTo  PROC_EXIT  EndIf  

Correct:

  '*Iftheuserdoesn'thavesecurityrightstodeleteanaccount,   '*saysoandgetout.   IfNot  (objApplication.Security.CanDeleteAccounts)  Then  MsgBox"Youdonothavesecurityrightstodeleteaccounts.",_ vbInformation  GoTo  PROC_EXIT  EndIf   '*Askforconfirmationbeforedeleting,andgetoutiftheuser   '*doesn'twanttodelete.   If  MsgBox("Deletethisaccount?",_ vbYesNo  Or  vbCritical)=vbNo  Then   GoTo  PROC_EXIT  EndIf  

9.8. Avoid using abbreviations. Unless your organization defines a documented set of words to abbreviate, you should avoid abbreviating words in your comments. Abbreviations often make comments harder to read, and people often abbreviate the same words in different ways, which can lead to confusion. If you must abbreviate, be very, very consistent. Say you have a human resources application that manages employees . Because the word employee appears in so many places, you might choose to abbreviate it as Emp. If you must do this, make sure that you do it consistently and that all other members of your team use the same abbreviation.

Incorrect:

  '*EnablethedelAcctmenuitem.  ActiveBar.Tools("DeleteAccount").Enabled=  True  

Correct:

  '*EnabletheDeleteAccountmenuitem.  ActiveBar.Tools("DeleteAccount").Enabled=  True  

9.8.3 Capitalize entire words to indicate their importance. To call attention to a word or words within a comment, use all uppercase letters . You can't apply formatting such as bold or italics because these features aren't supported by the Visual Basic code editor.

Correct:

  PrivateSub  UpdateDatabase()  '*Purpose:Updatethedatabasestructure.   '*DONOTUSEERRORTRAPPING!Lettheerrorscascadeupthe   '*callstack.    EndSub  

9.9 Indent comments to align them with the statements that follow.

Comments are generally positioned in front of the code they document. To visually reinforce the relationship between a comment and the code it relates to, indent the comment at the same level as the code. Some developers indent code lines a single tab stop from the comment they follow, but if you were to remove the comments from a procedure that used this indentation scheme, it would quickly become apparent that the indentation does not correctly reflect the structure of the procedure. The code is not subordinate to the comment; it coexists with the comment.

9.10 Give each procedure a comment header.

Each procedure should have a comment header. Procedure comment headers can contain documentation of items such as the input parameters, the return values, the original author, the last person who edited the procedure, the last date revised, copyright information, or even a programmer's favorite color.

You have to decide what's important in a procedure comment header in your environment. At the very least, the comment header should contain the purpose of the procedure. The purpose should be stated clearly and concisely. If a procedure needs a thorough explanation, give it one, but avoid excessive wordiness, as in, "The purpose of this function is to " The Purpose heading itself tells the reader this much. A typical procedure comment header looks something like this:

  PrivateFunction  ShowPrintDialog()  AsBoolean   '*Purpose:DisplaythePrintdialogboxandgetprint optionsfromtheuser.    EndFunction  

The next elements you should consider adding to your procedure comment header are the input (parameters) and output (return value) of the procedure. For example:

  PublicFunction  ConvertSQLtoCrystalFormat(strSQL  AsString  )_  AsString   '*Purpose:ConvertastandardSQLstatementintoavalid   '*selectionformulaforusewiththeCrystal   '*printengine.   '*Accepts:strSQL_avalidSQLstatement.   '*Returns:ACrystalselectionformulathatisequivalent   '*tothepassed-inSQLstring.    EndFunction  

By including the purpose, accepted parameters, and return value comments in a procedure comment header, you create a much more understandable procedure. When you document the accepted parameters, be sure to note any special considerations or assumptions. For example, if the procedure expects a parameter to be formatted or within a certain range of values, include that information in the comments. Finally, if a procedure modifies any global data either directly or by changing the value of a parameter passed by reference, document this behavior in the procedure comment header as well.

All procedure comment headers should be formatted in the same way, and each piece of information should be clearly differentiated. The previous comment header has a highly recommended format; a reader can easily scan the header's components for the necessary information. The format is shown below as a shell, with no information. This format is used consistently throughout this book.

  '*Purpose:xxx   '*Accepts:yyy   '*Returns:zzz  

Each heading ( Purpose , Accepts , or Returns ) is followed by two spaces (pressing the Tab key after typing the heading moves you to the proper location), a colon , another two spaces, and then the text for the heading. If multiple lines are required, you should indent subsequent lines to the start of the text after the colon, as shown below:

  PublicFunction  ConvertSQLtoCrystalFormat(strSQL  AsString  )_  AsString   '*Purpose:ConvertastandardSQLstatementintoavalid   '*selectionformulaforusewiththeCrystal   '*printengine.   '*Accepts:strSQL_avalidSQLstatement.   '*Returns:ACrystalselectionformulathatisequivalent   '*tothepassed-inSQLstring.    EndFunction  

In addition to documenting the purpose, parameters, and return value of a procedure, you can also include the following elements in a procedure comment header:

  • The original author of the procedure. This information can be handy when you need to ask the developer a question about the procedure or when you want to drop an e-mail bomb on the author of some particularly insidious piece of code. When you document the author, use the heading Created By .
  • The date the procedure was last modified, and who modified it. It's difficult to keep this information up to date, so if the information isn't so important to your organization, you might want to leave it out. For instance, if a developer modifies a variable name, he or she must update the last modified date and possibly the last modified name. Sometimes it takes more work to modify the date and the name than to make the actual change in the code. But if this information is vital to your operations, by all means keep it in the header. When you document the person who last modified the code, use the heading Last Modified By . When you document the date the procedure was last modified, use the heading Last Modified .
  • Changes to the procedure. If you're really a masochist, you can keep a revision history in the procedure comment header. This information can include the date of each revision and a description of what was done. In a multideveloper environment, you must also keep the name of the person who made the changes. Keeping such revision information takes considerable effort, so balance the pros and cons of doing so before adopting this strategy.
  • Copyright information. If you distribute your code to developers outside your organization, perhaps by selling source code or posting code to the Internet, you might want to include copyright information in each procedure or in the Declarations section of each module. You must determine the value of this approach, since it's easy for others to remove the information when they paste the code into their application. Also, if someone compiles the code into an application, no one will ever see the copyright information anyway. Still, if it is important to you, place the copyright information in the procedure comment headers or in the Declarations section of each module.
NOTE
Although Event procedures are similar to the procedures that you actually write, you do not need to document the parameters of an Event procedure. You also don't need to document simple property procedures that encapsulate module-level variables . I have omitted the procedure comment header from some examples in this book when I've felt that it would convolute the topic being illustrated .

Practical Applications

Every procedure should have a procedure comment header, and every header should contain at least the purpose of the procedure, the parameters accepted by the procedure, and any return value.

9.10.1 Document the purpose of a procedure in the procedure comment header.

Incorrect:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Thisfunctionacceptsaformnameandreturns   '*TrueiftheformisloadedandFalseifitisnot.    EndFunction  

Correct:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Purpose:Determinewhetheraspecifiedformisloaded.    EndFunction  

9.10.2 Document the parameters of a procedure in the procedure comment header.

Incorrect:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Purpose:Determinewhetheraspecifiedformisloaded.   '*Accepts:Thenameofaform.    EndFunction  

Also incorrect:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Purpose:Determinewhetheraspecifiedformisloaded.   '*Accepts:strFormName.    EndFunction  

Correct:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Purpose:Determinewhetheraspecifiedformisloaded.   '*Accepts:strFormName-thenameofaform.    EndFunction  

9.10.3 Document the return value of a function in the procedure comment header.

Incorrect:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Purpose:Determinewhetheraspecifiedformisloaded.   '*Accepts:strFormName-thenameofaform.   '*Returns:TrueorFalse.    EndFunction  

Also incorrect:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Purpose:Determinewhetheraspecifiedformisloaded.   '*Accepts:strFormName-thenameofaform.   '*Returns:Whetherornottheformisloaded.    EndFunction  

Correct:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Purpose:Determinewhetheraspecifiedformisloaded.   '*Accepts:strFormName-thenameofaform.   '*Returns:Trueiftheformisloaded,Falseifnot.    EndFunction  

9.11 Document code processes by using inline comments.

The most common type of comment is generally referred to as an inline comment. While the procedure comment header documents the basics of the procedure, inline comments document the code itself. The implementation details aren't described in the procedure comment header because they might change over time and they add unnecessary complexity to the header. The place to document the implementation of a procedure is within the procedure itself. Take a look at the following procedure, which determines whether a form is loaded:

  Function  IsFormLoaded(strFormName  AsString  )  AsBoolean   '*Purpose:Determinewhetheraspecifiedformisloaded.   '*Accepts:strFormName-thenameofaform.   '*Returns:Trueiftheformisloaded,Falseifnot.   OnErrorGoTo  PROC_ERR  Dim  intCounter  AsInteger   '*Sincereferringtoaformloadstheform,theproper   '*waytodeterminewhethertheformisloadedistoloop   '*throughtheformscollection,whichcontainsonly   '*loadedforms.   For  intCounter=0  To  Forms.Count_1  '*Ifthecurrentformisthespecifiedform,   '*returnTrueandgetout.   If  Forms(intCounter).Name=strFormName  Then  IsFormLoaded=  True   GoTo  PROC_EXIT  EndIf   Next  intCounter  '*Formwasnotfound;returnFalse.  IsFormLoaded=  False  PROC_EXIT:  ExitFunction  PROC_ERR: MsgBox"basMainIsFormLoaded"&vbCrLf&"Error:"&_ Err.Number&vbCrLf&Err.Description  ResumeNext EndFunction  

Notice how each decision is commented. As you read the code, the comments explain the implementation details. Try to place an explanatory inline comment at each construct, such as loops and decision structures. You should strive to make these comments clear and concise , but if something needs a detailed explanation, give it one. Since inline comments appear in the same location as the code they're describing, they're fairly easy to maintain. If you change the code, change the comment.

Practical Applications

Inline comments are the most common and most important comments. Use them to document the implementation of procedures, walking the reader through the various twists and turns.

9.11.1 Place a comment before every If statement. If statements make decisions that affect the flow of execution. Document each If statement within your code.

Incorrect:

  If  Command$<>""  Then  intLocation=InStr(Command$,strSearchString)  If  intLocation=0  Then   '*Usethedefaultinifile,assumingit'sintheapplication   '*path.  strINIFile=App.Path&"\tpssuite.ini"  Else   '*Extractthenameofthedesignatedinifile.  strINIFile=Mid$(Command$,Len(strSearchString)+intLocation)  If  Dir$(strINIFile)=""  Then  strINIFile=App.Path&"\tpssuite.ini"  EndIf   EndIf EndIf  

Correct:

  '*Lookforcommandlineoptions.   If  Command$<>""  Then  intLocation=InStr(Command$,strSearchString)  '*Ifaniniparameterhasbeenfound,attempttouseit.   If  intLocation=0  Then   '*Usethedefaultinifile,assumingit'sintheapplication   '*path.  strINIFile=App.Path&"\tpssuite.ini"  Else   '*Extractthenameofthedesignatedinifile.  strINIFile=Mid$(Command$,Len(strSearchString)+intLocation)  '*Ifthespecifiedfileisnotfound,use   '*thedefaultinifile.   If  Dir$(strINIFile)=""  Then  strINIFile=App.Path&"\tpssuite.ini"  EndIf   EndIf EndIf  

9.11.2 Place a comment before every Select Case statement. Like If statements, Select Case statements evaluate expressions that affect the flow of execution. They are often more complex than If statements. You should thoroughly document Select Case statements.

Incorrect:

  PrivateSub  txtSearch_KeyDown(KeyCode  AsInteger  ,Shift  AsInteger  )  SelectCase  KeyCode  CaseIs  =vbKeyPageDown  '*Moveforwardinthelistthenumberofvisiblerows.  datPhones.Recordset.MovegrdPhones.VisibleRows  CaseIs  =vbKeyPageUp  '*Movebackwardinthelistthenumberofvisiblerows.  datPhones.Recordset.Move-grdPhones.VisibleRows  EndSelect EndSub  

Correct:

  PrivateSub  txtSearch_KeyDown(KeyCode  AsInteger  ,Shift  AsInteger  )  '*Iftheuserpressedanavigationkey,adjustthelist   '*accordingly.   SelectCase  KeyCode  CaseIs  =vbKeyPageDown  '*Moveforwardinthelistthenumberofvisiblerows.  datPhones.Recordset.MovegrdPhones.VisibleRows  CaseIs  =vbKeyPageUp  '*Movebackwardinthelistthenumberofvisiblerows.  datPhones.Recordset.Move-grdPhones.VisibleRows  EndSelect EndSub  

9.11.3 Place a comment before every loop, including For Next loops and Do loops. Every loop has a purpose, and often that purpose is not intuitively clear. Regardless of the complexity of the loop, document it with a comment preceding the loop.

Incorrect:

  For  intIndex=1  To  lvwReleasedItems.ListItems.Count  '*Gettheserialnumberfromthelistitem.  strSerial=lvwReleasedItems.ListItems(intIndex).Text  '*Deletetheserialnumberfromthetransfertable.  strSQL="DELETE*FROMtblTransferSerials"&_ "WHERE[TransferNumber]="&_ m_lngTransferNumber&"AND[SerialNumber]="""&_ strSerial&""";" dbTransfers.ExecutestrSQL,dbFailOnError  Next  intIndex 

Correct:

  '*Loopthroughtheselectedserialnumbers,andreleaseeachone.   For  intIndex=1  To  lvwReleasedItems.ListItems.Count  '*Gettheserialnumberfromthelistitem.  strSerial=lvwReleasedItems.ListItems(intIndex).Text  '*Deletetheserialnumberfromthetransfertable.  strSQL="DELETE*FROMtblTransferSerials"&_ "WHERE[TransferNumber]="&_ m_lngTransferNumber&"AND[SerialNumber]="""&_ strSerial&""";" dbTransfers.ExecutestrSQL,dbFailOnError  Next  intIndex 

9.11.4 Place a comment before every statement in which a global variable is changed. As I discussed in Chapter 6, global variables are evil! However, if you absolutely need to use a global variable, document why you are changing it. This will make debugging a bit simpler.

Incorrect:

  PrivateSub  clsConnector_Terminate()  '*Purpose:Keeptrackofthenumberofautomation   '*clientsholdingreferencestothesuite.   OnErrorGoTo  PROC_ERR g_lngAutomationInstances=g_lngAutomationInstances-1 PROC_EXIT:  ExitSub  PROC_ERR:  Call  ShowError("clsConnector","Class_Terminate",Err.Number,_ Err.Description)  GoTo  PROC_EXIT  EndSub  

Correct:

  PrivateSub  clsConnector_Terminate()  '*Purpose:Keeptrackofthenumberofautomation   '*clientsholdingreferencestothesuite.   OnErrorGoTo  PROC_ERR  '*Decrementthecountofclientsholdingreferencestothis   '*connectorobject.  g_lngAutomationInstances=g_lngAutomationInstances-1 PROC_EXIT:  ExitSub  PROC_ERR:  Call  ShowError("clsConnector","Class_Terminate",Err.Number,_ Err.Description)  GoTo  PROC_EXIT  EndSub  

9.12 Use end-of-line comments to document variables.

Some developers use end-of-line comments, which appear at the end of a code statement and can extend for multiple lines. Try to use these comments for short descriptions only. If a longer description is necessary, use an inline comment instead. End-of-line comments were used more frequently in the past; most developers now choose (and rightly so) to use inline comments instead. The following is an example of an end-of-line comment:

  DoWhile  intLocation>0  '*Dowhileaspaceisfound.    Loop  

End-of-line comments tend to make the code more difficult to read when they are used in constructs such as the code snippet above. However, a good use of an end-of-line comment is for documenting the declaration of a variable whose purpose might not be clear, as shown here:

  Dim  objTaxReporterAsObject  '*MayholdanEmployeeobjectoran   '*Employerobject.  

When you use multiple end-of-line comments (such as for multiple variable declarations at the top of a procedure), attempt to align them. This makes them a little easier to read.



Practical Standards for Microsoft Visual Basic
Practical Standards for Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 0735613567
EAN: 2147483647
Year: 2000
Pages: 57

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net