The following is a collection of standards and practices to be observed while developing/enhancing/repairing Waukesha County (WC) web applications. It is expected that development be constrained to the following technologies:
XHTML JavaScript Cascading Style Sheets (CSS) XML |
ASP/VB Script ASP.NET/VB.NET ADO/ADO.NET SQL Server |
This document is organized with the following sections:
- Development Process
- Target Browsers and Industry Standards Compliance
- Naming and Folder Structure
- Comments
- General Coding Practices
- XHTML
- JavaScript
- Cascading Style Sheets (CSS)
- XML
- ASP/VB Script
- ASP.NET/VB.NET
- ADO/ADO.NET
- SQL Server
Practices to be strictly applied are prefixed with “REQ:” (required). Practices to be followed when convenient are prefixed with “Sug:” (suggested).
1. Development Process
- REQ: Development code will be controlled by Visual Source Safe. Any change to any file must be saved in source control at the end of each day.
- REQ: Development may occur on a local PC or on a development server.
- REQ: When promoting to the test environment, the entire set of project/application files, less configuration file, is copied to the new environment. The same is true for promotions to production.
- REQ: When the application or database is placed in a development environment, add the suffix _DEV to the name of the root folder or database, as ROD_TaxListing_Dev. In the test environment, use _TST, and in the production environ, use _PRD.
- Sug: The test environment is to be used only for second-party testing.
- See the Naming section for name requirements for the different environments.
2. Target Browsers and Industry Standards Compliance
Try to design to W3C standards for XHTML, CSS, and WCAG level A.
- REQ: Design all web pages to work acceptably on our specified browser of choice (currently IE 8 and 7) and the most recent version of the other most popular browser (currently Firefox).
- REQ: Specify document type definition declaration on each web page: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> . Observe XHTML coding standards.
- REQ: Specify namespace declaration in opening html tag: <html xmlns="http://www.w3.org/1999/xhtml" >
-
Sug: Design for W3C Web Content Accessibility Guidelines (WCAG) Level A compliance. Level A is W3C’s minimum accessibility compliance rating.
- A text equivalent for every non-text element shall be provided (e.g., via "alt", "longdesc", or in element content).
- Equivalent alternatives for any multimedia presentation shall be synchronized with the presentation.
- Web pages shall be designed so that all information conveyed with color is also available without color, for example from context or markup.
- Documents shall be organized so they are readable without requiring an associated style sheet.
- Redundant text links shall be provided for each active region of a server-side image map.
- Client-side image maps shall be provided instead of server-side image maps except where the regions cannot be defined with an available geometric shape.
- Row and column headers shall be identified for data tables.
- Markup shall be used to associate data cells and header cells for data tables that have two or more logical levels of row or column headers.
- Frames shall be titled with text that facilitates frame identification and navigation.
- Pages shall be designed to avoid causing the screen to flicker with a frequency greater than 2 Hz and lower than 55 Hz.
- A text-only page, with equivalent information or functionality, shall be provided to make a web site comply with the provisions of this part, when compliance cannot be accomplished in any other way. The content of the text-only page shall be updated whenever the primary page changes.
3. Naming and Folder Structure
One of the best aids to understanding an application is through the wording used for project, file, variable, and method names.
- REQ: For project names and application root folder names, use the format like ROD_TaxListing, where an abbreviation is used to indicate the department/division of the sponsor of the project, and the rest of the name provides a unique functional description. Note the upper case for the dept/div, the single underscore, and the Pascal casing of the project description.
County Board
CB
Info Technology
IT or IS
Corporate Counsel
CC
Land Info Systems
LIS
Circuit Court System
CCS
Parks and Land Use
PLU
County Clerk
CL
Purchasing
PUR
Dept. of Admin
DOA
Records Management
RM
Dept. of Public Works
DPW
Register of Deeds
ROD
Health & Human Services
HHS
Waukesha County
WC
Human Resource
HR
Waukesha Communications Center
WCC
- REQ: Databases should be named with upper case characters, and underscore characters used to prevent blank spaces. The database name structure is “sponsor_name_environment”, like “ROD_TAX_LISTING_PRD”. Environment suffixes of “_DEV” and “_TST” should be used where appropriate.
- Sug: Where a database corresponds to an application, the name of the database should parallel the application. Application: ROD_TaxListing_PRD, database: ROD_TAX_LISTING_PRD
- REQ: No spaces in URL’s. Hence, no spaces in file or folder names.
- REQ: Place all image, video, and sound files in a /media folder.
- REQ: For files that serve as auxiliary files to main or GUI files, precede name with abbreviation of usage type, as incHeader. This serves to identify auxiliary files, and group them according to type in an alphabetically ordered listing. This is not necessary for files with different extension names, as .css and .js.
Include
inc
User Control
ctl
Class
cls
- REQ: For file names, use camel casing (
winnerListing.asp
) where the first letter of each word except the first is capitalized. Constants should be all uppercase with underscores between words, such asNUM_DAYS_IN_WEEK
. For folders, properties, and methods, use Pascal casing (CalculateInvoiceTotal
) where the first letter of each word is capitalized. - REQ: For variable names, precede name with abbreviation of variable type (Hungarian notation). This is especially useful to discern the scalar variables (strUserName) from form components (txtUserName).
Integer
int
Guid
guid
Textbox
txt
String
str
Array
ary
Label
lbl
Boolean
blnl
Dataset
ds
Button
btn
DateTime
dt
Table
tbl
Listbox
lst
Byte
byt
SortedList
sl
Panel
pnl
Long
lng
Object
obj or o
Double
dbl
- REQ: A name should tell “who” or "what" rather than "how." For example, you could use “
aryStudents
”
instead of “array1
”
. Don’t be reluctant to use long names, like “SortStudentArrayForAdmissionTickets()”. - REQ: Do not use vague/ambiguous/generic words. Searches for instances of words like “user” or “edit” yields many useless hits. Instead, use names like ‘EditStudentRecord’ that will more likely be unique among all names.
- REQ: Use the verb-noun method for naming routines that perform some operation, such as
CalculateInvoiceTotal()
. When naming functions, include a description of the value being returned, such asGetCurrentStudentName()
. Boolean variables and Boolean functions should contain “Is”
which impliesYes/No
orTrue/False
values, such as blnFileIsFound
. - REQ: Use single-letter variable names, such as
i,
orj,
for
short-loop indexes only. - REQ: Include notation that indicates the scope of the variable, such as prefixing a
g
for global variables andm
for module-level variables. For example, gstrUserName. -
Sug: In object-oriented languages, it is redundant to include class names in the name of class properties, such as
Book.BookTitle
. Instead, useBook.Title
. - Sug: Use customary opposite pairs in variable names, such as min/max, begin/end, and open/close. Also, append computation qualifiers (Avg, Sum, Min, Max, Index) to the end of a variable name where appropriate.
4. Comments
Sufficient comments should be included in source code to allow any developer to understand the logic of the code without referring to external documentation. Strive to be clear and concise.
- REQ: At the top of each file, include a description of the purpose of the file and a modification log. At the top of each method, include a description of the purpose of the method. For variable declarations, include an in-line comment describing the purpose of the variable if not made clear by the name of the variable.
- REQ: Use comments for loops and logic branches. These are key logic areas.
- REQ: Separate comments from comment delimiters with one space—easier to see where developer cannot see color-coding. Do not surrounding a block comment with a typographical frame—use white space instead.
5. General Coding Practices
- REQ: Source code should reflect a harmonized style, as if a single developer wrote the code in one session. Harmonized style and repeated techniques are easiest to read.
- REQ: Limit source code line length to 80 characters. When a code statement is broken across several lines, indent the subsequent lines. Makes for easier screen viewing and cleaner hardcopies.
- REQ: Sections of code should be vertically delimited by blank lines. For example, methods should have two or three blanks lines separating them from surrounding code. Loop structures should have one blank line separating them from surrounding code.
- REQ: Indent code structures in two-space increments. Where braces are used to demarcate code structures, align the opening brace with the closing.
- For Each item In collection
- A = B
- If A = TRUE Then
- C = D
- End If
- Next
for (i = 0; i < 100; i++)
- { A = B
- if (A == true)
- {
C = D
}
- }
Q. REQ: Use a space after each comma in comma-delimited lists, such as array values and arguments, when doing so does not alter the intent of the code.
R. REQ: Use spaces before and after most operators. An exception is in HTML, where attributes (class=”tableHead”) are easier to read with no spaces around the operator.
S. REQ: Declare local variables just prior to where they are used, not necessarily at the top of the code as some advise. Localized declaration provides a better indication of where and how the variable is used, and makes it more likely the variable will be removed when its associated code is removed.
T. Sug:Keep the scope of variables as small as possible. Instantiate object instances as late as possible, and explicitly destroy object instances as soon as possible.
U. Sug: Use variables and routines for one and only one purpose.
V. REQ: Refer to database fields by field name; do not reference fields by their ordinal placement. Reference by placement is not as readable, and is prone to break.
W. Sug: Use Select Case
or Switch
statements in lieu of repetitive checking of a common variable using If…Then
statements.
X. Sug:Critical program errors should be reported to an error log or the Windows Application Event viewer.
Y. Sug: Remove all unused code prior to deployment. Rely on back-up copies of the source code to store code that “someone might use some day”. At the least, move unused code to the end of the file so that it can be out-of sight/out-of mind.
Z. REQ: If a password will be stored into a data table, and stronger encryption techniques are not specified, it will be encrypted using the MD5 hash methodology.
6. XHTML
- REQ: Observe XHTML rules. Use lower case for all tags. Use lower case for attribute and attribute values. Use double-quotes for attribute values where possible; otherwise, use single-quotes. Always provide closing HTML tags. For self-closing tags, place the slash at the end of the tag (<br />).
7. JavaScript
- Sug: Minimize the usage of JavaScript as much as possible.
8. Cascading Style Sheets (CSS)
- Sug: NO styling should occur in-line, all styling should occur in the linked .CSS file.
9. XML
- Sug: XML File formats should be used for any transfer of data from one system to another.
10. ASP/VB Script
- REQ: Make use of a single, global configuration module (config.asp) to declare and define global parameters, or parameters that are likely to be modified over the life of the code.
- REQ: Use
Option Explicit
to minimize errors resulting from typographical errors. - REQ: Any created objects should be removed from memory when no longer used, for example “Set objName = nothing”.
- REQ: Use script delimiters (<% %>) around blocks of script rather than around each line of script. Using script delimiters around each line or interspersing HTML fragments with server-side scripting increases the frequency of context switching on the server side, which hampers performance and readability.
11. ASP.NET/VB.NET
- REQ: Set project OPTION EXPLICIT and OPTION STRICT
- REQ: When writing classes, set fields/attributes for Private use only, then use Public or Protected get/set properties to expose fields needed by external code. This provides an opportunity to validate value changes, and indicates to other developers the scope of use of the field value.
- REQ: The format for .vb files (class and code-behind) is demonstrated below
- Description of file purpose.
- blank line
- Modification log
- blank line
- Compilation options (Strict and Explicit are required)
- blank Line
- Import declarations
- blank Line
- Class definition header
- blank line
- Field declarations
- blank line
- Property definitions with blank line between them.
- 2-3 blank lines
- Method definitions with 2-3 blank lines between them.
- blank line
- Class definition footer
- REQ: Only one class definition should be included in each file. For class definition files, the file name should parallel the name of the class. For the class definition above, the file name should be clsSample.vb.
- REQ: Disable Debug Mode in web.config before deploying an ASP.NET application to test or production.
- Sug: Use early binding techniques whenever possible.
- Sug: Do not use Exceptions for common input validation or messaging. Exception handling is resource intensive.
- REQ: When project namespace becomes an issue, for example, when a project needs a strong name to be placed in the Global Assembly Cache (GAC) or when a dll is being generated to use in other applications, use the name us.wi.Waukesha.co.doa.appname. For example, us.wi.Waukesha.co.doa.ROD_TaxListing where the name of the application is ROD_TaxListing.
12. ADO/ADO.NET
- REQ: To realize the benefit of database connection pooling, use a single database service account for all of the application’s users. May also be a single Active Directory account, provided the app runs under the security context of that account.
13. SQL Server
**The document SQL Server Standards is now available on the wiki, and supersedes this section.**
- REQ: Each non-log or non-backup table should include the following fields:
- PKId. Primary Key Identifier (guid or auto number).
- updateBy. Username of user that modified the record, set “unknown” as default value.
- updateDate. Date-Time record was modified, set getdate() as default.
- optLockCnt. Version counter, 0 by default and incremented on each update. Guards against dirty-data updates.
- REQ: Applications will always need to service at least the updateBy fields to provide username information (unless Windows Integrated Authentication is used—then a trigger will do).
- Sug: For thorough auditing, each table can have an insert/modify/delete trigger that copies each version of the primary table’s records to a companion table (named primarytablename_AUDIT) . Code like this can service the optLockCnt and updateDate fields of the primary table as well as perform the auditing function:
CREATE TRIGGER AppUser_auditAll ON dbo.AppUser AFTER INSERT, UPDATE, DELETE AS /* Universal audit trigger for SQL Server. Logs changes of primary table to companion table, services optLockCnt and updateDate fields. Assumes
AFTER Trigger tables (INSERTED and DELETED) cannot handle text, ntext, img data type columns. Audit bypasses these tables to get rows from primary table. */ DECLARE @errMsg varchar SET @errMsg = '' DECLARE @icount int SET @icount = (SELECT count(*) FROM INSERTED) DECLARE @dcount int SET @dcount = (SELECT count(*) FROM DELETED) IF @icount > 0 AND @dcount = 0 -- an insert operation BEGIN INSERT INTO AppUser_AUDIT SELECT * , suser_sname() FROM AppUser WHERE PKId IN (SELECT PKId FROM INSERTED) IF @@ERROR <> 0 OR @@ROWCOUNT = 0 SET @errMsg = 'Failed insert - audit insert.' END IF @icount > 0 AND @dcount > 0 -- an update operation BEGIN SELECT DELETED.optLockCnt, INSERTED.optLockCnt FROM DELETED INNER JOIN INSERTED ON DELETED.PKId = INSERTED.PKId WHERE (DELETED.optLockCnt) <> INSERTED.optLockCnt if @@ROWCOUNT <> 0 SET @errMsg = 'Failed update - dirty data.' ELSE BEGIN UPDATE AppUser SET optLockCnt = optLockCnt + 1, updateDate = getdate() WHERE PKId IN (SELECT PKId FROM INSERTED) if @@ERROR <> 0 OR @@ROWCOUNT = 0 SET @errMsg = 'Failed update - lock handler.' ELSE BEGIN INSERT INTO AppUser_AUDIT SELECT * , suser_sname() FROM AppUser WHERE PKId IN (SELECT PKId FROM INSERTED) if @@ERROR <> 0 OR @@ROWCOUNT = 0 SET @errMsg = 'Failed update - audit insert.' END END END IF @icount = 0 AND @dcount > 0 -- a delete operation. --Does not capture delete username. This must be captured by an application --or stored proc that performs update prior to delete. Also, does not attempt --to log data. See prior update for data state prior to delete. BEGIN INSERT INTO AppUser_AUDIT (PKId, optLockCnt, updateDate, updateBy, dbUserAcct) SELECT PKID, optLockCnt, getdate(), updateBy, suser_sname() FROM DELETED IF @@ERROR <> 0 OR @@ROWCOUNT = 0 SET @errMsg = 'Failed delete - audit insert.' END IF @errMsg <> '' BEGIN ROLLBACK RAISERROR(@errMsg, 16,1) END |
- REQ: If a password will be stored into a data table, and stronger encryption techniques are not specified, it will be encrypted using the MD5 hash methodology.
- Sug: Use stored procedures in lieu of views or ad hoc queries to leverage the performance gains they provide. Stored procs can also be nicely documented.
- REQ: Put each major SQL clause on a separate line so statements are easier to read and edit:
SELECT FirstName, LastName
FROM Customer
INNER JOIN Order
ON Customer.PKId = Order.FK_Customer
WHERE State = 'WA'
- Sug: Use upper case for clause statements, lowercase for SQL functions, and Pascal case (each word begins with a capital letter, no spaces) for table names and column names.
-
Sug: When naming tables, express the name in the singular form. For example, use
Employee
instead ofEmployees
. -
Sug: When naming columns of tables, do not repeat the table name; for example, avoid having a field called
EmployeeLastName
in a table calledEmployee
. - REQ: Do not prefix stored procedures with
sp
_, because this prefix is reserved for identifying system-stored procedures. Use the prefix “sp”, as in spGetData. - Sug: Minimize the scope and duration of transactions.
-
Sug: Use
RETURN
statements in stored procedures to help the calling program know whether the procedure worked properly. RETURN 0 is default, means success. Other codes indicate error -
Sug: Avoid
SELECT *
. Be explicit in which columns to retrieve and retrieve only the columns that are required. - Sug: When using LIKE, avoid using a wildcard character at the start of the match value because SQL Server will not be able to use the indexes.
-
Sug: Use
WITH RECOMPILE
inCREATE PROC
when a wide variety of arguments are passed, because the plan stored for the procedure might not be optimal for a given set of parameters. -
Sug: After each data modification statement inside a transaction, check for an error by testing the global variable
@@ERROR
. -
Sug: Use uncorrelated subqueries instead of correlated subqueries. Uncorrelated subqueries are those where the inner
SELECT
statement does not rely on the outerSELECT
statement for information. In uncorrelated subqueries, the inner query is run once instead of being run for each row returned by the outer query. - Sug: Use TRUNCATE TABLE instead of DELETE to clear all rows in a table. TRUNCATE TABLE does not log the changes in the transaction file, so it is faster and uses less resources (though it requires a security context greater than datawriter).