The purpose of this article is to present a basic yet complete coding style guide which you can use with your development team.
General Rules
The reason why a programming team has a style guide is for the sake of conformity. In other words, even though the code is worked upon by 3-4 different people, it should all look like it’s been written by one person. Conformity leads to better maintainability in the long run (e.g. bug fixing becomes faster and adding new features gets easier).
There are 3 ‘golden rules’ which should be followed when coding on projects, they are:
1. Functions should be no more than one screen length in size
2. Don’t do anything clever
3. Don’t do anything stupid
2. Don’t do anything clever
3. Don’t do anything stupid
Further explanation...
Functions should rarely be longer than one screen length in size. If you find you've written a function which is longer than one screen length in size, try break out a block of code into a separate smaller function if it makes sense to do so.
Also, if you see your function is performing two distinct tasks or operations, break it out into two smaller functions. For example; imagine you are calculating a user’s age, and then displaying their profile in the one function; that should be broken into two separate functions. This rule isn't always practical, you will occasionally get a long function if you have a large switch statement. You'll also get a long function if you have HTML/UI code to render. But at least 8 out of 10 times, functions can be written which are no more than a screen-full in size, this is definitely possible.
The reason why you should be writing small functions is utilising the OOP principle of modularisation. In the long run, this improves the maintainability of code and reduces bugs by breaking up tasks (functions) into smaller units. Imagine you have to come back to debug a block of code 3 months after writing it. Most likely your memory of the function would have begun to fade, it’s easier and quicker to get re-acquainted with a smaller block of code. Also, consider the very real possibility of someone coming back to debug your code, it’s going to be easier for them to understand a smaller block of code vs. a large slab of code.
“Don’t do anything clever” means don’t write unnecessarily complicated code. If you can write 3 lines of code which is easier to understand than 1 line of compact code and does the same thing, write 3 lines. Again, this comes back to maintainability. Someone else may need to debug your code later down the track, so do what you can to make it easier for. If it’s a very straight forward line of code, then it’s OK to put it on a single line - e.g.:
if (strFirstName = "") then Exit Function end if
“Don’t do anything stupid” isn’t about making mistakes, mistakes are mistakes - they happen, we’re all human. What we are talking about is doing things where you know better. For example: checking-in code before testing it, or not backing-up files before making major changes, or changing a password and not letting other people know about it, or having a problem with your work and keeping it to yourself, rather than telling your manager and asking for help.
CSS
This section relates to writing CSS code which is used by the software's front-end.
Class names should always be all lowercase:
Good: login_user_name
Bad: Login_User_Name
Separate each word with an underscore (not a space):
Good: login_user_name
Bad: loginusername
If you need to create a new CSS class, it must be placed in the
\css\main.css
file (or whatever file is considered the main CSS file for the software).
If you need to create a whole new CSS include file, it should be placed inside the
\css\
folder. Creating an entirely new CSS include is rare, it would only happen if for example you were adding a large new sub-system to the project (e.g. forum.css
).
CSS class names should be descriptive, but generally no longer than 3 words:
Good: menu_hover_over
Bad: m_hoverover
ASP Code
Even though vbScript is a loosely-typed language, it’s advisable to prefix variables with a data type. This occasionally helps with debugging as bugs occur due to data type mismatches.
Use the following data type prefixes:
i = for integer (e.g. iCounter)
str = for strings (e.g. strStudentName)
f = for floats (e.g. fDollarAmount)
obj = for objects (e.g. objRecordSet)
b = for bools (e.g. bRtnValue, bHasBeenDeleted)
...Arr = for arrays (e.g. strArrWeekdays, iArrProductIDs)
str = for strings (e.g. strStudentName)
f = for floats (e.g. fDollarAmount)
obj = for objects (e.g. objRecordSet)
b = for bools (e.g. bRtnValue, bHasBeenDeleted)
...Arr = for arrays (e.g. strArrWeekdays, iArrProductIDs)
When using bool values, use the naming convention of bHas... or bIs... (e.g.
bHasExpired
or bIsVisible
). This naming approach results in more readable code since you can write 'English-like' questions, for example:
if (bHasBeenDeleted = true) then...
Use camel notation for variable names:
Good: strFirstName
Bad: strfirstname
Bad: str_first_name
Generally, underscores aren’t used with variable names. The exception to this rule is global variable (which should be rare anyway), these should be prefixed with a g_...:
Good: g_strUserName
Bad: gstrUsername
Use descriptive variable names rather than short indistinct ones, but within reason. Try describing the variable within 3-4 words at most:
Good: iCounter
Good: iNumberOfStudentRecords
Bad: x
Bad: i
Bad: iTotalNumberOfStudentRecordsReturned ← unnecessarily long
It’s better to have a variable name like
iNumberOfItemsToShow
than iNoItems
. Descriptive variable names make code more readable, which improves maintainability in the long run and reduces debugging time. Imagine you have to come back to debug your code 3-4 months in the future, the code won’t be fresh in your mind. Also, think about people who may have to debug your code, descriptive variables will help them.
When working with arrays, consider creating constants to use with them. This is especially helpful if the array is intended for use within more than one function. For example:
const EMAIL_SUBJECT
const EMAIL_MESSAGE_BODY
strArrEmailTemplate(EMAIL_SUBJECT)
strArrEmailTemplate(EMAIL_MESSAGE_BODY)
const EMAIL_MESSAGE_BODY
strArrEmailTemplate(EMAIL_SUBJECT)
strArrEmailTemplate(EMAIL_MESSAGE_BODY)
This makes it clear what data is being held in the array element. This in turn reduces the risk of bugs in the long run.
Functions
This section talks about how functions should be written within code.
At the beginning of most include files (.inc), there should be a start-up function (e.g.
BlogStartUp()
). This is generally used for initialising global variables used within the module/include file:
Function BlogStartUp()
g_strArticleID = Response.QueryString("article_id"))
End Function
g_strArticleID = Response.QueryString("article_id"))
End Function
We use camel notation for function names, except the first letter of the function is always capitalised:
Good: LoginStartUp()
Bad: loginstartup()
Long function names are better than short undescriptive ones (within reason):
Good: GetNumberOfActiveStudents()
Bad: GetVal()
Bad: ProcessStudentRegistrationInformation() ← that’s far too long
You must use local variables as much as possible and pass values to functions, rather than rely on global values. It’s OK to use global variables occasionally, you just shouldn’t rely on them too much.
If you find you need to pass a large number of values into a function (e.g. 10+), consider passing an array of values instead. For example:
Good: Call SaveStudentData(strArrStudentDetails)
Bad: Call SaveStudentData(strStudentName, iAge, iEnrollmentStatus, iStreetAddress, strSuburb, strZip, iCampus, iGender, iCourseCode)
If you have a recordset object, you’re better off passing it to a function ByRef rather than sending a big list of parameters. For example:
Function DrawStudentSummaryList(ByRef objRecordSet)
When writing a new function, think about including some basic error checking if it makes sense. This is especially important when the function needs a passed value to work. For instance, imagine a SQL query like this within a function:
strSqlQuery = "SELECT * FROM tbl_users WHERE (status = " & iStatus & ")
What would happen if the iStatus parameter was empty? You'd get a script error. To avoid the danger of a crash, you should add a line of code at the top of the function which looks like this:
if (iStatus = "") then Exit Function end if
When a function is created specifically to return a value, prefix it with the word
Get...()
, for example:
Function GetAccountStatus()
Function GetNumberOfTickets()
Function GetUserFullNameByID()
Function GetNumberOfTickets()
Function GetUserFullNameByID()
Functions which perform some form of processing and then return a value should have a specific variable which has the data type plus the word
...RtnValue
. For example:
strRtnValue
iRtnValue
bRtnValue
iRtnValue
bRtnValue
When a function is written to save a value of some kind, it should generally be prefixed with the word
Set...()
, for example:
Function SetActiveMenuItem()
Function SetUserLastLoginTime()
Function SetUserLastLoginTime()
If a function contains HTML code and is rendering front-end UI of some kind, it needs to be prefixed with either Render...() or Draw...(), and post-fixed it with the word ...HTML(). For example:
RenderLoginBoxHTML()
DrawDateDropListHTML()
DrawDateDropListHTML()
Query Strings
When creating query string variables to be passed via hyperlinks, they should be named all lowercase with underscores in place of spaces. If an ID is being passed, then the query string name should end with ..._id (e.g. blog.asp?blog_id=45). Query string variables should be descriptive, but generally no longer than 3-4 words in length:
Good example:
<a href="blog.asp?blog_id=1">Buying a Cat</a>
Bad example:
<a href="blog.asp?ID=1">Camping</a>
Form Controls
Form fields should be named in a manner which gives an indication of their control type, for example:
<input type="text" name="txt_age" value="" maxlength="8" />
<input type="checkbox" name="chk_agree_to_terms" value="1" />
<input type="radio" name="rdo_gender" value="1" />Male
<textarea name="txt_about_me"></textarea>
<select name="drp_day"><option value="1">1</option></select>
This naming convention can be useful when it comes to server-side logic. Knowing the control type helps with debugging or processing data before inserting it into the database.
Notes:
1) textbox controls should always have their maxlength attribute set
2) textarea controls use the same prefix as textbox controls (it’s just text after all).
If you need to use an ID with a control due to JavaScript interactivity, the naming convention for IDs has the control type at the end rather than as a prefix. For example:
<input type="text" name="txt_age" value="" id="age_textbox" />
<input type="checkbox" name="chk_tax" value="1" id="tax_checkbox" />
<input type="radio" name="rdo_join" value="1" id="join_radio" />Yes
<textarea name="txt_about_me" id="about_me_textarea"></textarea>
<select name="drp_day" id="day_droplist"><option value="1">...
Note: the ID attribute is named differently to the form control name to avoid confusion between the two.
File Names
This section relates to the naming conventions used for all files found within the website’s folders.
File names should always be all lower case and use underscores instead of spaces:
Good: database_connection.asp
Bad: Database Connection.asp
Longer descriptive file names are preferable to short ones which give no indication of what the file is (within reason). Usually a maximum of 3-4 words will do:
Good: duplicate_username_check.asp
Bad: dup_check.asp
Bad: perform_duplicate_username_check_operation.asp ← too long
These same rules apply for all other file types like JPEGs and PNGs (note: GIFs are rarely used these days, they’ve mostly been replaced by PNGs).
The reason for descriptive file names is it helps when trying to identify what a particular file does amongst a larger list of files without having to open up the file.
Database
This section covers conventions to be used when working with database tables and fields.
The rules for naming database tables are as follows:
• use only lowercase characters
• use underscores in place of spaces
• table names are prefixed with the letters tbl_
• table names should rarely be more than 3-4 words in length
• tables should nearly always end in ‘s’ (indicating plural)
• use underscores in place of spaces
• table names are prefixed with the letters tbl_
• table names should rarely be more than 3-4 words in length
• tables should nearly always end in ‘s’ (indicating plural)
For example:
Good: tbl_students
Good: tbl_countries
Bad: Error Code ← should be: tbl_error_codes
Bad: UniversityStudentRecordDetails ← too long
Datababase fields should follow these rules:
• use only lowercase characters
• use underscores in place of spaces
• primary and foreign keys must start with id_
• rarely be more than 3-4 words in length
• use underscores in place of spaces
• primary and foreign keys must start with id_
• rarely be more than 3-4 words in length
For example:
Good: id_student
Good: first_name
Bad: enrolmentStatus ← should be: enrolment_status
Bad: recordID ← should be: id_record
Note: one of the reasons why primary keys always start with id_ relates to protecting against SQL-injection hacks. You can have a wrapper function like
QStr()
and RForm()
which strip the characters id_ from strings.
When creating fields used to store a bool condition (e.g. yes/no, active/inactive, show photo/don’t show photo, etc) - use a tinyint data type rather than a bit. 1 is used to indicate true and 0 represents false. Using an int provides flexibility in case more conditions are added in future (e.g. 1 = active, 0 = inactive, 2 = suspended).
Subscribe to RSS Feed.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.