1. Trang chủ
  2. » Công Nghệ Thông Tin

Visual Basic 2005 Design and Development - Chapter 15 pot

26 269 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 26
Dung lượng 468,2 KB

Nội dung

Coding Standards Coding standards are rules that developers follow to make their code more consistent. Consistent code is easier to read, so developers can understand and modify it more quickly with less chance of introducing new errors. For example, suppose I build an application that uses a First Name text box. My particular set of standards says the text box should be named txtFirstName, the associated label should be named lblFirstName, and, if I need to copy the text entered in the text box into a variable, the variable should be named first_name. If I see any of those items (txtFirstName, lblFirstName, or first_name) in the code, I know exactly what they are. Similarly, if I see items such as txtStreet, lblBillingCity, or cboState, I immediately know what the values are for, even without studying the code in detail. That makes my understanding of the code faster and more accurate. The object names in the previous paragraph use standard prefixes to indicate the types of objects that they represent. These are txt for TextBox, lbl for Label, and cbo for ComboBox. The section “Component Names” later in this chapter lists other object prefixes. It is important that all of the programmers on your project follow the same coding standard so that they can more easily read and understand each other’s code. It is less important, however, what standard you adopt. Consistency is the important thing, not whether you name variables using “Pascal case” ( FirstName), “camel case” (firstName), or lowercase with underscores ( first_name). The important thing is that all of the developers follow the same rules. Standards are also useful for preventing arguments. As strange as it seems, some developers can become quite heated when discussing the merits of Hungarian notation, camel casing, and the other niceties of coding conventions. Having a well-defined standard can defuse some of these arguments before they start. I’ve never worked on a project where these sorts of arguments were much of an issue. If someone found a situation that wasn’t covered by the standard, we took a quick poll to see what the devel- opers preferred and added it to practice. 21_053416 ch15.qxd 1/2/07 6:34 PM Page 409 In fact, that’s the approach I suggest you take for dealing with unexpected items. If you don’t have a rule to cover the situation, create one. It doesn’t matter much what decision you make, as long as you make one. This chapter describes my particular set of coding standards. It also describes some standards recom- mended by Microsoft developers and others. After you study the different standards, you can use their ideas to write your own standard that best suits your needs. Names Most Visual Basic statements include the names of subroutines, functions, variables, modules, enumer- ated types, and other program items defined by the user. Because programmers spend so much time reading these items, their names must be as easy to understand as possible. If the reader must spend even a tiny amount of extra time remembering what a name means, it can take a lot longer to under- stand the code. Picking good names can have a large impact on how easy it is to understand and maintain code, so developers have spent a lot of time and effort on naming conventions. The following sections describe some of the rules I use when naming variables. Hungarian Notation Hungarian notation is a system where you add characters to the beginning of a variable’s name to give extra information about its data type and scope. For example, the variable mblnReady would be a module-scope ( m) Boolean (bln) variable, and gaintCustomerIds would be a global (g) array (a) of integers ( int). The idea behind Hungarian notation was to make up for lenient compilers. A loosely typed language such as Visual Basic 6 will let you assign an integer variable to a string value, or vice versa. For that mat- ter, it will let you put an integer or string value in a form variable, and it won’t tell you there is a poten- tial problem until the code actually tries to make the assignment at run-time. If you use proper Hungarian notation, you should notice the problem as you write the code. For exam- ple, in the following code, that fact that the variable on the left is a form ( frm) and the value on the right is an integer ( int) should raise a warning flag for you: mfrmPlaces = intOrderCenters If you take Hungarian notation to the extreme, you should never have variables in the same assignment statement that have different data types. You should not even assign an integer value to a long integer variable without explicitly using a conversion operator such as CLng or CType. Although the motivation behind Hungarian notation is reasonable, I have rarely seen type and scope mismatches cause problems. However, I have often seen developers greatly confused by badly named variables. If you give variables good enough names, it is easier for the reader to remember what they represent. In many cases, the name can help the reader remember the data type as well. 410 Part III: Development 21_053416 ch15.qxd 1/2/07 6:34 PM Page 410 For example, if the integer variable in the previous example were named num_order_centers, it would be fairly obvious that it was a number and should not be assigned to a form variable. The Visual Basic .NET environment has also become much better at warning you when you try to make suspicious assignments. For example, it will raise an error if you try to assign an integer to a form vari- able. This makes Hungarian notation less important than it was in the past and, in fact, the Visual Basic documentation explicitly recommends that you not use it. In fact, I wish Visual Basic were even stricter than it is. For example, it won’t let you implicitly assign a long integer value to an integer variable because the long value might be too big to fit in an integer (this is called a “narrowing conversion” because the long is bigger or wider than the integer). However, it will let you assign an integer value to a long variable (a “widening conversion”). I would rather at least see an error message so that I have to think about the assignment and explicitly use CLng to make the conversion safely. Some developers would flag these issues as warnings instead of as errors. But if you ignore a bunch of warnings, it’s difficult to sift out the ones that are important from those that aren’t. I would rather fix every such instance with CLng, CType, DirectCast, or other conversion statements and not see a warning or error again. My goal is always to have no warnings or errors ever. For all of these reasons, I recommend that you don’t use Hungarian notation. It adds clutter to variable names and doesn’t really help all that much. Instead, focus on making the rest of the name as descriptive as possible so that the reader can remember what the variable means. The following sections give some tips on making variable names easy to remember. Component Names Components are different from other variables used in the code because you do not declare them yourself in your code. Instead, they are created on a form and the code can then refer to them. The fact that they are declared in this special manner gives them a slightly different status than variables declared within the code. Components are also very important to Visual Basic programs, and code often sets a variable’s value equal to some property of a component. To make the link between a component and its corresponding variable obvious, you should give them names that are similar. For example, you might store the text value taken from the txtFirstName TextBox in the variable first_name. Visual Basic developers often use three-letter prefixes to indicate a component’s type. For example, stan- dard abbreviations include txt for TextBox, lbl for Label, btn for Button, and so forth. The more recent versions of Visual Basic have added new controls that don’t have intuitive three-letter abbreviations. For example, in Visual Basic 6, the Common Dialog Control’s methods allowed the user to select a color, font, file for saving, or file for loading. It also provided methods for displaying help or a print dialog. The prefix for this control in Visual Basic 6 was dlg. Visual Basic 2005 uses separate components to handle these tasks: ColorDialog, FontDialog, OpenFileDialog, SaveFileDialog, HelpProvider, and PrintPreviewDialog. You could give them obscure prefixes such as cd, fd, ofd, sfd, hp, and ppd, but it would probably take awhile to grow accus- tomed to them. 411 Chapter 15: Coding Standards 21_053416 ch15.qxd 1/2/07 6:34 PM Page 411 Instead, I prefer to use slightly longer abbreviations that are easier to read. For these controls, I prefer these prefixes: dlgcolor, dlgfont, dlgopen, dlgsave, hlp, and dlgppv. The leading “dlg” on all of them (except the HelpProvider) makes it obvious that the component is a dialog. The rest of the prefix helps you remember which kind of dialog. If you really want to save a few keystrokes, you can abbreviate the abbreviations to dlgclr, dlgfnt, dlgopn, dlgsav, hlp, and dlgppv. I prefer to keep the names a little easier to read and let IntelliSense do the typing for me. The following table lists some suggested prefixes for the most common Windows forms components. Component Abbreviation Component Abbreviation 412 Part III: Development BackgroundWorker bw BindingNavigator nav BindingSource bsrc Button btn CheckBox chk CheckedListBox clb ColorDialog dlgcolor ComboBox cbo ContextMenuStrip ctx DataGridView dgv DataSet ds DateTimePicker dtp DirectoryEntry dir DirectorySearcher srch DomainUpDown dud ErrorProvider err EventLog log FileSystemWatcher fsw FlowLayoutPanel flo FolderBrowserDialog dlgfolder FontDialog dlgfont GroupBox grp HelpProvider hlp HScrollBar hbar ImageList il Label lbl LinkLabel llbl ListBox lst ListView lvw MaskedTextBox msk MenuStrip mnu MessageQueue que MonthCalendar mcal NotifyIcon nico NumericUpDown nud OpenFileDialog dlgopen PageSetupDialog dlgpage Panel pan PerformanceCounter pc PictureBox pic PrintDialog dlgprint PrintDocument pdoc PrintPreviewControl ppv PrintPreviewDialog dlgppv Process proc ProgressBar pbar PropertyGrid pgrid RadioButton rad 21_053416 ch15.qxd 1/2/07 6:34 PM Page 412 ReportViewer rpt RichTextBox rch SaveFileDialog dlgsave SerialPort port ServiceController serv Splitter split StatusStrip ss TabControl tab TableLayoutPanel tpan TextBox txt Timer tmr ToolStrip ts ToolStripContainer tscon ToolTip tip TrackBar tbar TreeView tvw VScrollBar vbar WebBrowser wbr 413 Chapter 15: Coding Standards You can find many lists of name prefixes on the Web. Microsoft has a fairly large one at support.microsoft.com/kb/q173738. Constant Names For constants, I use uppercase words separated by underscores, as in the following example: Const MAX_USERS As Integer = 10 This makes it obvious that a value is a constant. Unfortunately it doesn’t indicate the constant’s scope. A constant looks the same whether it is declared within a subroutine, at the module level, or globally. I have rarely found this to be a problem, however, at least partly because constants make up such a small fraction of the symbols in a typical application. It’s just not that hard to track down a constant on those rare occasions when you need to know where it was declared. Routine Variable Names I declare variables within a subroutine using lowercase with underscores separating words, as shown in the following example: Dim num_items As Integer Dim total_cost As Decimal Dim sales_tax As Decimal Parameters to a routine are declared within the context of the routine, so I treat them as routine-level variables and also declare them using lowercase with underscores separating words. For example, in the following code, the file_path and file_title parameters follow this naming convention: Public Sub LoadData(ByVal file_path As String, ByVal file_title As String) End Sub Component Abbreviation Component Abbreviation 21_053416 ch15.qxd 1/2/07 6:34 PM Page 413 Other Names For names that are not constants and that are not declared within routines, I use Pascal case (with the first letter in each word capitalized). For example, a method that generates a new invoice might be called GenerateNewInvoice. Items whose names appear in Pascal case include namespaces, modules, classes, properties, methods, events, Enums, Enum values, module-level variables, global variables, events, and interfaces. I prefix module-level variables with “ m_” and global variables with “g_” to indicate their scope. For example, the following code declares a variable for use within a class: Private m_DataIsDirty As Boolean Public variables declared with a class have normal Pascal case names with no leading scope indicator. Using scope indicators is a common technique used by many Visual Basic developers, but I’ve seen some strange uses. On one large project that had been running for a very long time, some of the devel- opers clearly didn’t understand what the m_ meant, and you could find variables declared inside sub- routines that began with m_. Because the rule wasn’t applied consistently, it was almost useless. Like most developers, I add the letter “ I” before an interface name. For example, an interface for draw- able objects might be called IDrawable. I do not add a “ C” before class names as in CEmployee or CCustomer, although many developers do this. Microsoft recommends that you do not. When I define an enumerated type, I add “ Types” to the end of the name. That lets me use the same name (minus the “ s” in “Types”) as the name of a property having that type. For example, the following code uses the ShapeTypes enumeration that defines some shape types. The ShapeType property has type ShapeTypes. Public Enum ShapeTypes Line Ellipse Rectangle Polygon End Enum Private m_ShapeType As ShapeTypes Public Property ShapeType() As ShapeTypes Get Return m_ShapeType End Get Set(ByVal value As ShapeTypes) m_ShapeType = value End Set End Property 414 Part III: Development 21_053416 ch15.qxd 1/2/07 6:34 PM Page 414 The code implements this property by using a private variable named m_ShapeType. This variable has the same name as the property with the m_ scope indicator to show that it is private to this class. Boolean Names When you declare something that has a Boolean data type, give it a name that includes a form of the verb “to be.” Use normal capitalization rules to indicate the item’s type and scope as usual (for example, is_running, is_dirty, WasHandled, or m_WillBePrinted). The name should sound like a statement of truth and not a question. If the value does not refer to the “current” object, you may need to put the form of “to be” inside the name, rather than at the beginning if you want it to sound like a statement. For example, in the Order class the IsDirty property indicates that the Order’s data has changed. The property applies to the current Order object, so the statement IsDirty makes sense for that object. If an Order object’s code refers to several printers, it might use the variables printer1_is_ready, printer2_is_ready, and so forth, to refer to their readiness. The names is_printer1_ready, is_printer2_ready, and so on, sound more like questions than statements. The final test is to try the name out in a Boolean expression. The following statement is fairly easy to read: If printer1_is_ready Or printer2_is_ready Then The following statement is more awkward: If is_printer1_ready Or is_printer2_ready Then This version is harder to read, so it will take longer to read and is more likely to lead to misunderstanding. Abbreviations Ideally, you would avoid all abbreviations in names. Spelling out words makes names easier to under- stand, and if you use IntelliSense properly, it doesn’t really take more time to type. Abbreviations can also lead to inconsistencies among developers. For example, different developers might name a variable that holds the number of employees as number_of_employees, num_employees, num_emps, or no_emps. In practice, however, some abbreviations are extremely common. The .NET Framework uses min and max to mean “minimum” and “maximum” in several places, so those seem like safe abbreviations. Many developers also use num for “number” so that also seems reasonably safe. In some applications, it may also make sense to use industry-specific abbreviations. When I was work- ing at a GTE Laboratories, abbreviations such as pots (Plain Old Telephone Service) and mark (referring to another application, Mechanized Assignment and Record Keeping) were common. 415 Chapter 15: Coding Standards 21_053416 ch15.qxd 1/2/07 6:34 PM Page 415 To keep things consistent, make a list of allowed abbreviations and add to it when necessary. Try to spell words out and use IntelliSense to make typing them easier. However, if everyone in the office already uses certain abbreviations, it sometimes makes the code more consistent and easier to read to use them in the program as well. Escaped Names Visual Basic allows you to use keywords in names by surrounding the name in square brackets. The fol- lowing code shows a function named Sub that takes a parameter named New. The code uses brackets to differentiate these names from the Visual Basic keywords Sub and New. Private Function [Sub](ByVal [New] As Integer) As Integer If [New] < 10 Then [New] = 10 If [New] > 100 Then [New] = 100 Return [New] End Function If this code is contained in a class, other code within the class could invoke the function using either of the following statements: Debug.WriteLine([Sub](1)) Debug.WriteLine(Me.Sub(1)) This code is confusing and difficult to read. Don’t use escaped names unless absolutely necessary. The only situation I know of when you really need to use escaped names is when you are using a library or other tool that uses Visual Basic keywords for names. For example, C# does not have the ReDim key- word, so it is possible that someone writing a library in C# might create a class named ReDim. To use that class in Visual Basic, you must surround the name with brackets, as in the following statement: Dim redimmer As New [ReDim] Even then you could use the library’s fully qualified name, as in this version: Dim redimmer As New ReDimLib.ReDim The ReDimLib example solution available for download at www.vb-helper.com/one_on_one.htm includes a C# library that defines a simple ReDim class and a Visual Basic program that uses it. I’ve never heard a plausible reason why you would need to use keywords for names in code that you write. Class Names Use nouns or noun phrases for class names. Classes define objects, which are things, so their names should be things as well. Some good class names include Customer, Report, StartTime, and DispatchStrategy. Note that some names such as Customer and Report are in some sense tangible, whereas others such as StartTime and DispatchStrategy are not. 416 Part III: Development 21_053416 ch15.qxd 1/2/07 6:34 PM Page 416 Property Names Make the names of properties nouns or noun phrases such as TextColor, LineWidth, or Straightness. A property is a characteristic of an object, and these names sound like characteristics. Microsoft recommends that you consider naming properties after their data types, if that makes sense. For example, if a class needs a font property, you could name it Font. The following code shows how a class might declare a Font property of type Font: Private m_Font as Font Property Font() As Font Get Return m_Font End Get Set(ByVal value As Font) m_Font = value End Set End Property This can sometimes lead to confusion (particularly because it’s not as easy to make a property named after an enumerated type that you create within the class), so I usually prefer to change the name slightly. For example, you could change this property’s name to TextFont. Method Names A subroutine makes an object do something, so its name should reflect that by indicating an action. Give subroutines names that are verbs or verb phrases. For example, some good subroutine names include PrintInvoices, DeleteItem, and Execute. Avoid names that could be interpreted as either nouns or verbs. For example, don’t use the name Color for a subroutine that colors a shape, because someone reading the code might read Color as a noun and assume it is a property rather than a subroutine. Usually, you can avoid this issue by adding an extra word. In this case, you could change the subrou- tine’s name to ColorShape. A function is similar to a subroutine except that it returns a value. Because a function returns a value, it is usually more natural to treat the function as a noun instead of a verb. For example, the following code calls the driving_map object’s BestForeColor function and saves the result in a form’s ForeColor property: Me.ForeColor = driving_map.BestForeColor() In cases such as this one, there is practically no difference between a function and a read-only property. Both make the most sense with names that are noun phrases, both return a value, and you cannot assign a value to either. 417 Chapter 15: Coding Standards 21_053416 ch15.qxd 1/2/07 6:34 PM Page 417 Sometimes it’s difficult to decide whether to implement a feature as a function or a property. The follow- ing list gives some reasons why you might want to choose one or the other: ❑ If the action is a conversion function such as ToString, Microsoft recommends that you use a function. ❑ If the action takes a long time, use a function. Properties are expected to be fast. ❑ If the action has side effects, use a function. Properties should not have side effects. ❑ If the action returns an array, use a function. Properties that return arrays can be confusing. ❑ If you want to serialize the value, use a property. ❑ If you want to display values in a PropertyGrid or other property editor, use a property. This is most useful if the developer must set the value at design time, or if the user must set it at run-time. ❑ If you want to notify the program when the value changes, use a property and an associated property changed event. For example, if the program might need to know when the MinimalPathLength value changes, make it a read-only property and raise the MinimalPathLengthChanged event when it changes. It is more natural and traditional to asso- ciate an event with a property than with a function. Event Names For events that occur before the code takes some action, end the event’s name with the “ing” form of a verb, as in Clicking, Changing, Moving, or Canceling. For events that occur after the code takes some action, end the event’s name with a verb in the past tense, as in Clicked, Changed, Moved, or Canceled. Make the rest of the name explain the thing to which the verb applies—for example, SeatClicked, CustomerChanged, DrawingObjectMoved, or JobSchedulingCanceled. Microsoft recommends that you add EventHandler to the end of event handler names, as in the follow- ing code: Public Delegate Sub SeatClickedEventHandler(ByVal seat_clicked As Seat) This makes sense when you are declaring a delegate. Later, when you declare a variable with the dele- gate’s type, the name makes it easier to understand that this is an event handler. Dim clicked_event_handler As SeatClickedEventHandler In Visual Basic, it is traditional to name an event handler by using the name of the object raising the event, followed by an underscore and then the name of the event. The Visual Basic code editor names events this way if you use the drop-downs to build an event handler. The event handler name is the same as the name in the Handles clause, except the dot is replaced with an underscore. The following code shows how the code editor would name the SeatClicked event raised by an object named m_SeatingChart: 418 Part III: Development 21_053416 ch15.qxd 1/2/07 6:34 PM Page 418 [...]...21_053416 ch15.qxd 1/2/07 6:34 PM Page 419 Chapter 15: Coding Standards Public Sub m_SeatingChart_SeatClicked(ByVal seat_clicked As Seat) _ Handles m_SeatingChart.SeatClicked End Sub Sometimes you might want to create an event handler yourself without using the code editor’s dropdowns For example, suppose you create several Drawable objects at run-time, and you want to use AddHandler to associate... underscore and the name of the event: DrawableMoved The form’s Load event handler adds some Drawable objects to the list and uses AddHandler to associate the NetworkObjects_DrawableMoved event handler with the objects’ DrawableMoved events Declaring Variables In Visual Basic 6 and earlier versions, it was common practice to declare all variables at the beginning of a routine If you were reading code and needed... declares the variable i in the For statement: 420 21_053416 ch15.qxd 1/2/07 6:34 PM Page 421 Chapter 15: Coding Standards ‘ Print the employees’ work assignments For i As Integer = 0 To num_employees – 1 ‘ Print this employee’s work assignment Next i The Using statement introduced in Visual Basic 2005 takes this idea a step further Visual Basic not only makes variables declared in a Using statement... last point drawn, and the opposite corner either measured at an absolute position or relative to the first corner This single routine did way too much It should at least have been split into Line and Rectangle methods, and probably into separate absolute and relative versions Visual Basic NET’s Graphic’s class solves this problem by providing separate DrawLine and DrawRectangle methods, and not allowing... flow and jump out of the routine at any point I don’t follow this rule rigorously, but I do try to make a routine’s exit points as obvious as possible I often allow a routine to begin with validation and error-checking code, and the code can exit if the validations fail After that, the routine should have a single exit point, if possible 430 21_053416 ch15.qxd 1/2/07 6:34 PM Page 431 Chapter 15: Coding... recommended by Microsoft is its Web page “.NET Framework General Reference, Design Guidelines for Class Library Developers” at http://msdn.microsoft.com/library/en-us/cpgenref/html/cpconNETFramework DesignGuidelines.asp One of the less-obvious rules in my coding standards is to always provide Else and Case Else blocks for long If Then and Select Case statements If you don’t expect those cases to occur, then... different signatures so that Visual Basic could tell them apart For example, suppose a method draws some text The first version of the method takes some text (a string) and a font size (an integer) as parameters, while a second version takes the desired height of the text (an integer) and some text (a string) as parameters The order of the parameters is switched solely because Visual Basic will not allow you... System.Windows.Forms.PaintEventArgs) Handles Me.Paint Using thick_pen As New Pen(Color.Blue, 15) e.Graphics.DrawEllipse(thick_pen, Me.ClientRectangle) End Using End Sub When the Using block ends, the Pen is Disposed and the variable is destroyed If the Using block is long, add a comment at the end reminding the user of the variables created by the Using statement and of the block’s purpose Another feature introduced in Visual Basic. .. only its first name and street address parameters: Dim cust As New CustomerWithOptional(“Rod”, , “1337 Leet St”) Optional parameters also allow you to use named parameters The following code shows another way you can make a new CustomerWithOptional object while specifying only the first name and street address: 424 21_053416 ch15.qxd 1/2/07 6:34 PM Page 425 Chapter 15: Coding Standards Dim cust As... Select Case blocks Use comments at the end of code blocks, including If Then and Select Case statements, to remind the reader about the block’s purpose 432 21_053416 ch15.qxd 1/2/07 6:34 PM Page 433 Chapter 15: Coding Standards While I don’t recommend requiring that all methods have a single exit point, restrict the number and position of exit points Usually, it’s sufficient to begin a routine with . Assignment and Record Keeping) were common. 415 Chapter 15: Coding Standards 21_053416 ch15.qxd 1/2/07 6:34 PM Page 415 To keep things consistent, make a list of allowed abbreviations and add to. this control in Visual Basic 6 was dlg. Visual Basic 2005 uses separate components to handle these tasks: ColorDialog, FontDialog, OpenFileDialog, SaveFileDialog, HelpProvider, and PrintPreviewDialog variable with the dele- gate’s type, the name makes it easier to understand that this is an event handler. Dim clicked_event_handler As SeatClickedEventHandler In Visual Basic, it is traditional

Ngày đăng: 14/08/2014, 11:20