Free, Open-Source ASP.Net 2.0 Framework for Data-Driven Websites
Coding guidelines are always created with the good intentions of establishing consistency within a team and sharing best practices and lessons learned. The problem is that most developers flip through the document when it’s handed out and never think to look at it again.
The issue is project work is too fluid and a developer will ignore a section on threading if it isn’t applicable today, but when a threading issue comes up, she’ll just work to solve the problem and not think to review the document.
So our intention is to tackle the two goals of the typical guideline document in two different ways.
To capture best practices and lessons learned, we will use the blog as it is a better living document. If you want to leverage your fellow developer’s lessons learned about a topic, search the blog before you search the web. Maybe someone has posted something. If not, you’ve got some learning to do and that’s why we hired you. When you dig into and learn new things, we’ll ask you to write something about it so we can post it to the blog for others to learn from.
This document will address ensuring consistency in all of the code delivered through our shop. You’re a professional and we want you to have a great deal of freedom to solve the problems you encounter. That being said, there is a lot to be gained by taking a consistent approach to some things.
One of the most important benefits of consistency is human discovery and understanding of your code. How many times have you been asked to make a simple change to a page and ended up re-writing it because you just didn’t understand how it was structured or organized? If you’ve been developing for very long, it has likely happened often.
So what can we do about?
We can start by acknowledging that creating code that is discoverable and understandable to other developers is a critical factor in the long-term success of a project. As you make decisions about how you will code something, it should be as central in your decision making as other factors including developer efficiency, performance, and scalability.
Over time, we’ve found the two topics that have the largest impact on creating discoverable and understandable code are how files are organized and how things are named. This document will address both of these topics.
ASP.Net 2.0 Project Organization
There are two types of code within a typical project that must be accounted for: Reusable code that solves commonly-encountered problems; and Module-specific code used only for one module or function in the application.
Reusable Code can be found as classes stored in an App_Code folder, and as other items found in the Assets folder.
In App_Code, you will find a Classes folder and sometimes a WebService folder. In the Classes folder, you will find the following sub-folders:
You will also find reusable code in the Asset folder in the following folders:
Other folders will generally be added to the Assets folder based on the project. It is where all binary files like PDFs or SWFs should be stored.
Module-based code is stored module-specific folders at the root of the project. Generally, you will find one folder for each module. In our chamber project for example, there is a folder at the root level named Chamber.
In each folder for a module, you will generally find the following files:
It’s very common to add other pages to the module specific folder. Sometimes there will be a report about that type of item so a Report.aspx page may be added. If 10 of the 40 modules for a project require a report, then all pages added to the module-specific folder should be named the same thing.
We are consciously choosing to break tasks across multiple pages to keep the pages as simple as possible. If you have been around long enough to inherit someone else’s code, and that developer put a lot of tasks, screens, or functions into a single file, you likely found it much harder and much more time consuming to make even minor changes. You also have to regression test at a much deeper level because it’s possible you have impacted more functions of the page than you realize. So keep it simple and keep things separate.
Links between pages are done with good old-fashioned links and redirects. It’s not hard to go into a page and change a link if it needs to go someplace different, and today’s development tools make it very easy to discover all links to a page and change them. Many developers like to centralize control and the display of various forms via a controller of some kind. We keep it simple because we cannot find a critical problem a controller approach solves with the business-centric solutions we normally build, and we’re not going to introduce a complex tool that limits human discovery if there’s no real problem with the simpler approach.
ASP.Net 2.0 Naming Conventions
Everybody always starts the naming convention discussion talking about Pascal Case or Camel Case or one thing or another. Think about the projects you’ve looked at that were developed by others. Did Pascal vs. Camel casing really have much impact on how easily you could understand the code? Probably not.
These are the rules that we think really matter.
Rule number 1 in naming: Every layer of the application should use the same name for the entity and its properties.
The most critical aspect of naming is consistency of names from the database all the way through to the UI. Yes, in some places it should be Pascal and in others it should be Hungarian, but seeing ChamberName in the database and then seeing txtChamberName in a form found in a Chamber folder probably made it very easy for you to make some correct assumptions.
Tables should be singular nouns that are not reserved words (see SQL Coding Guidelines). The Domain class should have the exact same name as the table and every property in the Class should be an exact match of the column names in the database. The folder at root for the module represented by the table should also be the exact same name, and every instance of a control within the pages that refers to a column in any table should have the same name as that column.
Rule number 2 in naming: Do not abbreviate unless it is a common abbreviation that every developer will understand, and do not use single character variables.
We know, we know … it sucks to have to type “chamberCount” and “chamberLength” instead of “x” and “y” or “cc” and “cl”, but it will make your code much more understandable.
We will make you change your code if we find variables we do not understand during code reviews.
Rule number 3 in naming: Always list the full path of the class type when declaring variables for types that are not commonly used.
Too often, I pick up someone’s code and I see something like Dim cert as X509Certificate. I don’t know about you, but I don’t have the first clue what X509Certificate is so I have to right-click and go to definition, then come back to the page and try to pick up where I left off. What I would much rather see is Dim sslCertificate as System.Security.Cryptography.X509Certificates.X509Certificate. Yes, it’s a lot more that you have to type, but it might help another developer understand your code without jumping around a lot.
We are vigilant about this as well so get used to it as well.
Now, let’s get on with traditional naming conventions. The goal of these conventions is to help you avoid conflicts between variables scoped at different levels.
The following example will illustrate most of the conventions we try to adhere to.
Namespace UnfiedASP.Business Public Class Sample Public PublicVariable As String Private myPrivateVariable As String Const myConstant As String = "Value" Public Enum PublicEnum EnumOption1 EnumOption2 End Enum Public Property PrivateVariable() As String Get Return myPrivateVariable End Get Set(ByVal value As String) myPrivateVariable = value End Set End Property Private ReadOnly Property IsSomething() As Boolean Get Return True End Get End Property Public Function PublicFunction(ByVal parameter1 As String) As Integer Dim localVar1 As String Dim localVar2 As Integer End Function Public Sub DoSomething(ByVal parameter1 As String) End Sub End Class End Namespace
Controls should be Hungarian using the following prefixes.
| Control | Prefix | Example |
| Button | btn | btnSave |
| Calendar | cal | calRecordDate |
| Checkbox | chk | chkIsActive |
| Compare Validator | cpv | cpvPassword |
| DropDownList | ddl | ddlStateId |
| GridView | grd | grdChamber |
| HyperLink | hlnk | hlnkEdit |
| Label | lbl | lblChamberName |
| Literal | lit | litChamberName |
| Panel | pnl | pnlUsername |
| RadioButton | rad | radBlue |
| Regular Expression Validator | rev | revEmailAddress |
| Repeater | rep | repChamber |
| Required Field Validator | rfv | rfvChamberName |
| Script Manager | scm | scmPage |
| TextBox | txt | txtChamberName |
| Update Panel | upn | upnUsername |
| Update Progress | upr | uprIndicator |
| Validation Summary | val | valSummary |