I'm the Igloo Coder, and I'm starting to embrace my new Alt lifestyle.
Probably the most distracting things were Justice's insistence that Little House on the Prairie had to be on in the background and the fact he would constantly say Charles' lines just before they were said on the TV. Some people just think that they have to be the center of attention. I did catch him with my camera phone, during a break in the TV action, actually playing a hand. Look at his intense concentration. I think he knew that Rockarts was bluffing.
I'm the Igloo Coder and here's hoping that NDoc 2 gets revived by a group of people who were as passionate about it as the last.
Last winter I spent a bunch of time working as a maintenance/support programmer on this application and one thing became clear to me. When I went into the code I was never confident that the changes that I was making weren't breaking something larger than what I was working with. This was very nerve racking as I was regularly making hot fixes to the application and when fixing a bug the last thing you want to do is introduce a new problem. I know that writing tests will not prevent this from happening, but I would have like the comfort level that a well written test provides.
One of the most tried and true ways for developers to test their code is to try different scenarios in the belief that these manual tests will cover all possibilities. No matter how good a programmer or manual tester you are, there is no way that you can test and then state with certainty that you've covered all situations. For the lines that you didn't know that you didn't run, you have potential time bombs. Instead of risking these situations, I'd rather write tests and then strive to getting code coverage that nears 100%. The closer to 100% that I can get, the more likely I have eliminated all erroneous code.
The third reason that I'm making this push is non-coding. As your software grows and the complexity of its functionality increases you will begin to exert more and more pressure on your test team. While unit testing is not a replacement for real people testing, it can be used to relieve some pressure from them. If you know that you only touched some logic in a specific business function and that code is still passing all the tests, you probably can get away with a less vigorous manual test regime.
The last reason that I'm an advocate of having tests created is that they work as specifications embedded in the code base. You can look at a unit test(s) for a specific function and know exactly how that function is supposed to work. If you have no unit test to provide this information to you, you will have to search through the code in the function and hope it is correct, and that you read it correct, to determine how the code is functioning. Worse yet you will have to spend countless hours digging through design docs, change requests and other supporting documentation so that you can piece together the most recently signed off functionality for that part of the system. Having done this myself, you can trust me that it is not any fun.
Overall the spirit of testing is to provide a quick and consistently repeatable batch of code level tests that can aid in the verification of system functionality. Having tests provides another level of business knowledge to the developer, and it's in an environment that they are comfortable with. On top of all of this, unit tests can help, but don't guarantee, with increasing the quality of the code that your team turns out.
I'm the Igloo Coder and today I'm hot....hot and bothered....so quit pissing me off.
First let's talk about Hungarian Notation. If you've read my previous posts on naming conventions, you'll know that I prefer Hungarian Notation is a number of different situations. This is not one of them. If you open Enterprise Manager (SQL Server 7 & 2000) or SQL Management Studio (SQL Server 2005) you will notice right away that all your tables, stored procs and user defined functions are grouped under one node in a treeview control. Prefixing your tables with the names 'tbl' or 'tb' or 't' does not help you group your items together any better. It doesn't help to make your T-SQL code to be any more readable. If it does neither of these things, why bother? All you're doing is clutter screens and code.
PascalCasing is the other naming convention that I've used for table names. It's pretty simple to explain this. All your SQL objects are named with PascalCasing.
There are one thing that you need to be aware of when naming some objects. First *never* prefix stored procedure names with 'sp'. SQL Server sees this as a special value and will immediately look for the stored procedure in the Master database followed then by your database (this takes time and time is a huge part of relative performance). If you name your stored procedure with any other prefix ('xx' for example) SQL Server will looking your database base first.
The next thing I want to touch on is the fact that all of these objects will appear in T-SQL at some point. T-SQL has a pretty specific and orderly syntax to it. Table Names always appear after a FROM in a SELECT statement. Stored Procedures can't be called inline. User Defined Functions can be called inline in T-SQL. Because of this syntax these syntaxical orderings there are no compelling reasons to differentiate your objects based on a naming convention. Where they appear in the T-SQL will tell you exactly what they are.
Naming Stored Procedures is an interesting subject. I had a very long discussion, on the patio of a favourite local establishment, with a friend who made a very interesting argument on the verb and noun ordering when naming the stored procedure. Historically I've named my stored procedures verb-noun (i.e. GetCustomers or UpdateEmployees). This friend argued that he preferred the opposite syntax, noun-verb (i.e. CustomerGet, CustomerUpdate, EmployeeUpdate). His reasoning was that by using this ordering all the stored procedures related to one noun object (Customers for example) will appear grouped together in the treeview in SQL Management Studio. I'd never considered this, but when choosing your naming convention for stored procedure you will most likely be choosing between grouping them by functionality (verb) or domain object (noun). Since talking with him about this (and sobering up some) I've began to convert myself to the noun-verb syntax. I like knowing where all major operations on my domain objects are occurring.
My choice for all SQL objects is PascalCasing, with a noun-verb ordering on those that need it.
While doing a little bit of research on this topic, I was surprised to find that nobody, Microsoft included, wants to explore more than one possible way to name UI controls. Although, I'm sure that I'm not the first, allow me to explore a few of them now.
I've never seen either camaelCasing or PascalCasing used when naming controls in either a web or forms application. Although the consistent use of either in your code may work I can think of scenarios where it fails. If you have chosen to implement a standard where you are using camelCasing on your local variables, referencing a control will look exactly the same. The same would be true if you chose to implement PascalCasing for local or module variables and controls. For example:
As you can see in this example, not only does the definition of the control and the local variable look identical, but the IDE will not allow you to have the two different items available. So there you have it, *Casing your controls while using that same casing convention for local variables will cause you no end of grief as you fight naming collisions all over the place.
The much maligned Hungarian Notation appears to have found a home in the naming of controls. Everywhere you see says that you should never use Hungarian Notation in your code. Yet, even the books I'm using for reference explicitly state that controls should be prefixed with a type identifier. The Practical Guidelines and Best Practices for MS Visual Basic and C# Developers book even goes so far as to list the prefixes that it suggest you use for both the ASP.NET controls and HTML controls. Even more amazingly this book advocates the usage of the letter 'h' as a pre-prefix to identify HTML controls. Apparently
In all honesty, I've only ever worked on projects that have used Hungarian Notation as the naming convention for controls. After reading and considering the recommendation for pre-prefixing HTML controls with the letter 'h', I'm starting a slow conversion. Hungarian Notation eliminates all naming collisions that I described in the *Casing section. Like arguments in my previous posts, I think that the use of Hungarian Notation also helps by increasing the readability of the code.
10 TextBox txtFirstName = new TextBox();
12 public void MyMethod()
14 string firstName = txtFirstName.Text;
I personally prefer the use of Hungarian Notation when naming my user interface controls. I like the clarity, and, after some exploration of other options here, I also like that you have minimal chance of control vs. variable naming collisions.
Of all the items that I'll write about in this series, naming conventions for interfaces will be the easiest. I have only ever seen one way of naming interventions in any project that I've worked on. Not only that, I can't find more than one example of an interface naming convention in books or online. As much as most places suggest PascalCasing and camelCasing for all things, including Microsoft (thanks to the Coding Hillbilly for this....I'll bring a bottle of 'shine to your place next time we go trapping squirrels), nobody seems to be able to shake the Hungarian Notation recommended for interface naming. The only naming convention ever discussed for interfaces says that all interface names should be prefixed with a capital "I" followed by PascalCasing for the remainder of the name.
9 public interface ICanRefrigerate
11 //some stuff
Super (Base) Classes
Naming conventions for super or base classes should follow the same naming convention used for standard classes. The one difference is that you want to make the names of this type of classes both meaningful and useful as suffixes when they are inherited. In the following example you can see how the Car base class works nicely in both the SuperCar and RacingCar classes that inherit from it. The name of the RacingCar class clearly indicates that it is a "type of Car" or inherited from the Car base class.
14 public class Car
16 //some stuff
19 public class SuperCar : Car
21 //different stuff
24 public class RacingCar : Car
26 //other stuff
I'm the first to admit that I didn't present many options here. In these cases there aren't many options, no matter how accepted or rejected, to present. I use the "I" prefix for interfaces and I also use the Super/Base class suffixing format as well.
We have two primary goals on the development team. First we are trying to keep to our release schedule so we can meet our final release date. Next we are attempting to have a 0 bug count at the time we do our every two week release. The first goal is a matter of life and unemployment (or perhaps lower employment). The second goal is a great one to strive for, but it's a difficult one to achieve. So far we've had two code drops and we've had 0 and 1 bug carry over on each of those.
Where am I going with all this you ask? Well, the conversations with my coworker center around his, and admittedly mine too, urge to release bug fixes as quickly as we possibly can. In my mind this is a good trait for a developer to have. My coworker wants to get the best code, with the most functionality, to the testers and the business in the most timely fashion. This is perfect. A developer that's concerned about quality and punctual delivery. There is one drawback though, and I'm not sure how to strike the right balance with it.
Because we are performing continuous development cycles, we have to do our bug fixes at the same time as we are working on new code and in the same code base. This is fine but for the times that we want perform non-scheduled releases of bug fixes. So far I've been been managing this by fighting the urge to release more often than scheduled. I am however prepared to, and slightly reorganizing the work orders to help accommodate, build when a defect that seriously impeded the progress of the testers is raised. In my mind this takes an exceptional case.
One of the reasons I'm fighting both my and my coworker's urges to release each time bugs are fixed, is that I think this can set a very dangerous precedence with the test team. If the testing team becomes comfortable with us jumping to fix and build on every defect raised event, they will begin to expect and ultimately demand that we do this at all times. This ties in with my second reason for not doing on demand bug fix builds: Time, effort and scheduling. Each time you perform a build, uninstall the previous version from the servers, install the new version and perform a smoke test you have eaten up time. Depending on your project and schedule, time may be a valuable and rare commodity. In my environment each build requires the following efforts to get to a state where testing can resume.
- coordinate with development team to ensure that the code base is in a state that the testers will find acceptable
- Kick start build process (Forced through CruiseControl.NET)
- Uninstall previous version from the developer's test servers
- Install new version to the developers test servers (no xcopy here)
- Smoke test software in the developer test environment
- Notify test team that their environment will be upgraded
- Wait for test team to reach "good stopping points"
- Uninstall previous version from test environment
- Install new version to test environment
- Smoke test software in the test team's environment
- Notify test team of the upgrade's completion and which fixes were included with it
Perhaps releases every two weeks is as nimble as we should strive for. If any of you have experienced this situation and are willing to share some of your thoughts with me, please do. I'd really appreciate any ideas that you may have.
I'm the Igloo Coder and every time I take some of my ice flow to melt for water my situation gets a little more precarious.
One of the very first things that I want to say is that, like any other variable, class names need to be meaningful. If the name of the class doesn't properly represent the business/domain object it represents or the functionality it provides it will not be effective. From a developers perspective you also need to ensure that you make your classes easy to find. Don't create a class and name it and it's file two different things. I have seen this done and it is makes the code very difficult to work with. I know the VS IDE allows for this to happen, but most developers will look in the Solution Explorer for a file that has the exact same name as the class they are working with. If they're working with a class that appears in intellisense as 'Car', they will overlook the class in Solution Explorer that is named 'Automobile.cs'. In the end both of these recommendations serve two purposes: Readability and maintainability.
PascalCasing and camelCasing are both very viable options for naming classes. While preparing to write this post I was unable to come up with any discernable differences between the usage of either naming convention. The only thing that I could find was a recommendation by the Framework Design Guidelines book to use PascalCasing.
At one time I worked on a project (back in my VB6 days) where all classes were prefixed with 'cls', all forms were prefixed with 'frm' and all modules were prefixed with 'mod'. In the VS6 IDE you could easily tell each of those different items apart by the little icon that appeared next to them in the Solution Explorer. Today, using VS 2003/5, everything is a class. Imposing this convention in the VS 2003/5 environments would lead to absolutely everything being prefixed with 'cls'. Once you have everything using the same prefix, the prefix no longer has any meaning or usefulness.
I use PascalCasing when naming my classes. I'm not sure why I use it over camelCasing, but I do. In the end either would work, but only if you use your choice consistently.
Marcia's first comment was about the difficulties in finding adequate locations to hold events. We here in Edmonton have been very luck to get sponsorship of the facilities we require from the Edmonton Public Library. She makes a valid point that some places, such as Cape Cod, might not have the facilities readily available to them. One of the things that I want to point out is that the number of requirements for a meeting location is quite small. In my mind you need only the following
- Electrical outlets (preferably two)
- Adequate seating for your expected attendance numbers
- One table for the presenter and projector
- A surface to project onto (does not have to be a projection screen)
Marcia's second comment was a request to know how we at Edmug divvied up the work needed to keep the group running. One of the very first things that we did was download the INETA white paper on Starting and Running a User Group. From that document we decided to use the suggested leadership structure of President, Vice-President, Membership Director, Program Director and Treasurer. As I outlined in my Running with the Right Crowd post, one of our goals was to ensure that the leadership did not get burned out or become disinterested in the operation of the group. The division of tasks were never discussed at length. Most of the people in our leadership group stepped up to the plate and offered to take on the tasks that best fit with their role. As it stands now, here's a rough guide of what the person in each role is responsible for.
Arguably, this is one of the most difficult, and important, roles in the leadership group. Because of this we have kept the tasks that this role is responsible for to a minimum. The treasurer is responsible for finding, coordinating with and maintaining relationships with our cash and venue sponsors. As part of their work with new sponsors, it's the treasurers job to gather items such as pamphlets, business cards, electronic logos, etc. from the sponsors and hand them over to the group for inclusion on our website and event hand out materials.
The main area of responsibility in this role is making and maintaining contact with the attendees at our events. This includes the management of our membership list, the creation and distribution of monthly newsletters and the gathering of the feedback forms filled out during our meetings. The Membership Director also is responsible for ensuring that there is a table just outside our meeting room to hold the handouts and any free products we have to give away. They also man this table to ensure that all attendees are greeted and receive the appropriate handouts and feedback forms as they arrive. Because our Membership Director works very close to the meeting location, he has also taken on the responsibility of ordering, paying and setup of the catering we receive from the local coffee shop. An additional task that has fallen into the Membership Director's purview is the hardware requirements of the meeting. The primary reason for this has been that his employer is providing us with the projector we use during our meetings.
The primary focus of our Program Director is to liaise with prospective and confirmed speakers. The person filling this role is also responsible for anything related to the speaker on the day of the event. In addition to performing this role, our Program Director has made Edmonton Code Camp his baby and is heading up that initiative with support from the rest of our user group leadership.
This role has the least amount of formal task assignments in our leadership. The primary purpose of this role is to fill in for the President if they can't make a meeting or, as happened to us, the President decides that they must no longer be involved. In an effort to make as much use of this person as possible, they have been stuck with some of the more menial tasks. Right now the VP is responsible for the all important donut order on meeting nights. We've also started to get him to manage some of our new initiatives (watch for the Edmug Evangelist program!). Overall this roll has a "help out where required" task assigned to it.
My primary role as the president is to coordinate the other leaders. Because we have segmented the roles and responsibilities in the way we have, it is very important that someone works to ensure that the reliances and overlaps between different roles are managed efficiently. An example of this is the reliance of our Program Director on having monies available, from our Treasurer, for bringing in speakers. In this case it's my role to ensure that the Program Director knows in advance how much money is available for him to use on speakers. Another task that has been assigned to the President is the creation of the handouts and pre-meeting scrolling PowerPoint slide show. The President is also tasked with attracting and working with swag sponsors and collecting and transporting swag to the events. Like the VP, the President has a huge roll as an extra set of hands for helping to get things done. This will include the standard helping with event setup tasks as well as helping grease the wheels of the INTEA/MSDN Canada machines.
I hope that this better explains the roles that we are performing and how the operational tasks are distributed amongst the people that are helping to run the group.
14 //more readable
15 if (objHashTable.Contains(strSomeValue))
17 //do stuff
20 //less readable
21 if (objHashTable.IsContained(strSomeValue))
23 //do stuff
Because I use PascalCasing on my functions and methods, I also use PascalCasing on properties to ensure consistency.
Function and Method Names
Function and method names require a greater amount of attention be paid to the context of the name rather than the format that it is written in. From the Practical Guidelines and Best Practices for VB and C# Developers and Framework Design Guidelines book I can offer the following list:
- Avoid underscores
- Avoid names longer than 25 characters if exposed publicly
- Use verb, verb-noun or verb-phrase syntax
- Maintain a consistent naming convention for methods or functions that perform similar or opposite operations (i.e. If you have an Open method, have a Close method)
Probably the more common of the two options I'm presenting here is PascalCasing. This convention is often used across all functions and methods no matter if they are publicly or privately declared (both books beside me make this recommendation). Rather than dwell on the finite details of this convention, I'm going to offer two examples and move on.
9 public bool IsEmployerBankrupt()
11 //some logic
14 public void EvaluateCandidates()
16 //some logic
Not as commonly used, but still with a foothold as a standard is the use of camelCasing for function and method names. I personally have never worked with this standard. Here are examples.
19 public bool isEmployerLiquidating()
21 //some logic
24 public void splitHairs()
26 //some logic
Like function and method naming, there are two things to keep in mind when creating parameters. Of course you want to ensure that you are adhering to the naming standards set forth on your project, but you also want to consider what syntax you give the parameters. One of the best recommendations (I'm not sure where I saw this) that I've seen is that all constructor parameters should be named exactly the same as the properties that they are setting inside the constructor. This leaves little ambiguity as to the purpose of the parameter. Another great recommendation is to not include reserved parameters for future development. Reserve values, whether its for parameters, enums or something else, only serve to clutter and confuse the code space. A great recommendation, from the Framework Design Guildelines book, is to use enums instead of boolean values to increase the readability of the calling code. Take the following function definitions and resulting calls for example.
29 public void EvaluateJobCandidates(JobCandidate candidate, bool hasInterviewed, bool hasOffer, bool hasExperience, bool canStartImmediately)
31 //some logic
34 public void SomeFunction(JobCandidate candidate)
36 EvaluateJobCandidates(candidate, true, false, true, true);
39 public void EvaluateJobCandidates(JobCandidate candidate, InterviewStatus interviewStatus, OfferStatus offerStatus, ExperienceLevel experienceLevel, StartingTimeframe startTimeframe)
41 //some logic
44 public void SomeFunction(JobCandidate candidate)
46 EvaluateJobCandidates(candidate, InterviewStatus.Completed, OfferStatus.NoneMade, ExperienceLevel.Intermediate, StartingTimeframe.TwoWeeks);
Rather than make individual comments on PascalCase, camelCase and Hungarian Notation for the naming convention of parameters, I'm going to generally comment about them. As few, some or all of your methods, functions and constructors will be exposed publicly for consumption and use, you should be very concerned about how you expose these values for this is what people will associate with your code or framework. Consistency is very, very important here. If you are naming your classes or enums using a PascalCase (or camelCase for that matter) standard you will probably want to avoid using that standard for the naming of the parameters your function, method or constructor requires. If you look at the following image you can see that the tooltip is quite confusing when both the type and the parameter have the same casing.
My other suggestion is not to use Hungarian Notation for anything that your classes expose publicly. I've worked on a project where the Hungarian Notation convention was imposed on the parameters of methods, functions and constructors and it did nothing but clutter the space. Unlike searching for local or module level variables, when you start typing a method, function or constructor you are presented with a handy tooltip (see above) that offers great insight into the types for the different parameters.
Although I'm a Hungarian Notation guy, I do limit it to use on private variables only. The standard that I practice here is PascalCase for my method and function naming combined with camelCasing for my parameters.
I'm the Igloo Coder and I think I might have to go to Australia for the work environment
The list of naming conventions considered for use at the module level is usually quite similar to those considered for use in local variable situations. This list can include camelCasing, PascalCasing, Hungarian Notation, Single Letter Hungarian and SCREAMING CAPS. Being able to differentiate between module and local variables and consistency between different naming areas (i.e. Local and Module) are usually the primary factors considered when selecting the convention.
Differentiating between module and local level variables can be accomplished in a number of different ways. Below I will outline a few of those ways and the benefits and dangers each may pose.
I have worked on a number of projects where the module variables were prefixed with the underscore character. This convention accomplishes the two important factors of easy identification and consistency with other conventions. Underscore prefixes clearly indicate that a variable has been defined at the module level. The use of the underscore also can be used as an extension of the local variable naming convention employed. In this way it allows for all variables, module or local, to employ the same naming convention.
9 //Underscore Prefixing
10 //combined with camelCase
11 string _firstName;
12 int _cowCount;
14 //combined with PascalCasing
15 string _FirstName;
16 int _CowCount;
18 //combined with Hungarian Notation
19 string _strFirstName;
20 int _intCowCount;
Like the Underscore Prefixing convention, I have worked with "m" Prefixing as well. "m" Prefixing also shares a lot of features with Underscore Prefixing. Instead of prefixing your module level variables with an underscore you would prefix with a lower case letter "m". This convention also offers a number of benefits, but also has some drawbacks. "m" Prefixing allows for the consistent use of a single variable naming convention across local and module level variables. One of the problems with using the letter "m" as a prefix arises when the standard naming convention has leading lower case letters such as camelCasing and Hungarian Notation. When this occurs, the "m" prefix will tend to blend into the overall variable name which reduces it's effectiveness as a quick identifier of module level declaration.
22 //"m" Prefixing
23 //combined with camelCase
24 //note how the "m" does not clearly stand out
25 string mfirstName;
26 int mmachineCount;
28 //combined with PascalCasing
29 string mFirstName;
30 int mMachineCount;
32 //combined with Hungarian Notation
33 //note how the "m" does not clearly stand out
34 string mstrFirstName;
35 int mintMachineCount;
Unlike the last two conventions, this is a combination of two naming conventions. The combination of camelCasing and PascalCasing leverages the case sensitivity available in some programming languages. Because of it's reliance on case sensitivity, this convention will not work in VB.NET, but will in C#. To employ this convention you must choose one of the two *Casings for use at the local variable level and the other will then be used for module level variable naming. One of the benefits of this convention is that you have no cluttering of the code space with extra characters. There are a couple of problems with this convention. The first issue is that there the difference of one letters casing is not an easily recognizable identifier of module level declaration. Another issue is that by employing two naming conventions, one for local variables and the other for module variables, you have increased the responsibility of the programmers declaring variables. Programmers can easily implement reversals of the correct naming conventions (i.e. using PascalCasing when camelCasing is called for). In addition to these problems, programmers also can make mistakes in their usage of the variables if both local and module defined variables differ only by case. It is entirely possible, and quite probable, that a programmer will, at some point, work with the incorrect variable simple because they did not case the variable as they intended. Issues like this can create very difficult debugging exercises as no compile time validation of this occurrence can be preformed.
After having used all three of these conventions I have found that I get the best results from using the Underscore Prefixing convention. I find that it is very easy to identify a module level variable when it is used at any point in the codebase. I also am fond of how it can lead to using only one naming convention (Hungarian Notation is my personal choice) with the slight addition of an underscore.
I'm the Igloo Coder and my build is not broken.
I have seen a number of different naming conventions for local variables and I'm sure there are ten times more than that. As I've said before, none of these are right and none are wrong. The one thing to know is that no matter which of these naming conventions are implemented they will not make up for poorly named or overloaded variables. A variable named Cat should never contain a Dog. Naming conventions can neither rectify nor prevent this from occurring. That task resides firmly in the hands of the developer.
The Practical Guidelines and Best Practices book recommends using camelCasing for local variables. This keeps your code quite clean and leaves no doubt what the semantics of the variables are. One of the major drawbacks with *Casing conventions is that more than one is usually implemented together (if the programming language allows you to, which C# does and VB.NET does not). This can lead to some very difficult to trace bugs. By separating the semantics of two variables solely based on the casing of their names you have increased the amount of thinking that a developer has to do and the amount of information that they have to retain.
In short, camelCasing for local variables will create clean looking code, but you have to watch for case sensitive languages creating semantic differences based solely on capitalization.
9 private void camelCasing()
11 //Good use of camelCasing
12 int countOfItems;
13 string firstName;
15 //Bad use of camelCasing
16 //It's far to easy for a developer
17 // to incorrectly use one or the
18 // other variables and have no
19 // compile time checking.
20 //This is not possible in VB.NET
21 int countOfCows;
22 int CountOfCows;
The most verbally abused variable naming convention of them all, Hungarian notation, must still be included in this list. Most books (including both that I'm referencing) and people scoff at Hungarian as a throw back to days past when programmers had to work with much poorer tools than we have today. Like every other naming convention there are some good and bad points to this convention. One of the worst things that Hungarian notation does is overloading of the name of a variable. By adding a prefix indicating the variable type you have now tied that variable to both programmatic and business domains. It can also be argued that the convention prevents you from changing the variable's type without altering it throughout the codebase. Some would argue the opposite of that and say that changing the variable's type should require you to revisit its use throughout the codebase as a way to ensure the proper use of the variable with it's new type. One of the most common arguments against Hungarian notation is that modern development environments provide alternate methods (such as mouse-over tooltips) to determine the type of a variable. The opposite of this argument is that using Hungarian notation provides instantaneous feedback with no need to make mouse movements.
In conclusion, Hungarian notation adds some clutter to your variable names, but it can improve the readability of the code.
25 private void HungarianNotation()
27 //Hungarian notation
28 string strFirstName;
29 int intCount;
30 MyCustomClass objSomeName = new MyCustomClass();
This is a variant of Hungarian notation that I have used while working with one lead developer. The practice of Single Letter Hungarian (it may have some other name that I don't know) is to prefix all variables with one single letter which indicates the variable's type. Like Hungarian notation, this naming convention adds some extra clutter to your codebase. Unlike Hungarian notation, that clutter is 1/3 the size. One of the biggest issues that surfaces when using this convention is that you are limited to 26 prefix characters and you will inevitably run into conflicts. An example is the use of the letter 's' for both short and string types. The only way around this is to select a different letter for one of the two types and use it consistently. Unfortunately this will still result in reduced code readability.
Single Letter Hungarian notation is a compromise between the ease of type identification and the additional code clutter of prefixes. Unfortunately the 26 letter prefix pool is a significant drawback to the useability of this naming convention.
33 private void SingleLetterHungarian()
35 //Single Letter Hungarian Notation
36 string sFirstName;
37 int iCount;
39 //Problem area.
40 string sAmount;
41 short sCurrency;
42 //Less readable option for short types
43 short hCurrency;
This naming convention is rarely used but bears mentioning for a couple of reasons. One of the great things about SCREAMING CAPS is that variables will stand out very clearly when you are reading the code. Although they stand out from the surrounding code, variables following this convention and having compound words in them are not as easily read as those using the *Casing formats. The one place that SCREAMING CAPS has found a home is in the naming of constants. The code still has the same readability problems as I just outlined for SCREAMING CAPS used on variables, but using this naming convention on constants will keep them very distinguishable from variables.
While capitalization plays a role in all naming conventions, SCREAMING CAPS is less readable than strategically capitalized letters.
46 private void SCREAMINGCAPS()
48 //SCREAMING CAPS notation that is difficult to read.
49 string FIRSTNAME;
50 int COUNTOFCOWS;
51 MyCustomClass SOMECUSTOMCLASS = new MyCustomClass();
53 //SCREAMING CAPS notation for constants
54 const string ACONSTANTVALUE = "blah";
At one time or another I have worked with all of these naming conventions. As I've outlined above all have their good and bad points. For a number of reasons my personal preference is to use Hungarian notation. Now that I've got all your hackles up let me explain why.
One of the benefits of Hungarian notation is that it provides you with instant variable type feedback. I can hear your moans and exclamations that I can get that by mousing over the code or looking for the definition (either manually or by right clicking and selecting Definition). The truth is, I'm a keyboard jockey. The less I have to use my mouse the better I am. If I have to mouse over or right click and select Definition to determine the type of a variable I feel like I've just wasted some productivity, perhaps even dropped out of 'the zone' slightly. If I use Hungarian notation I can read my code and say "Yep, strFirstName is a string". My hands are still on the keyboard and I'm on my merry way.
The second reason that I favour this naming convention is because of the one thing it doesn't let me do. Although I can easily change the type of a variable from string to int, my variable now looses context. Like the good little programmer that I want to be, I can not allow the following to appear in my code.
56 int strCount;
I want to refactor out the incorrect prefix so that I adhere to the naming standard (variable prefix matching the variable type). I know that you are thinking that I now have the painful task of changing that variables name everywhere that it's being used. I like that I have to do this. Now I must revisit the use of the variable in all situations to change the variable name, and while I'm doing this I can ensure that I haven't introduced any unforeseen problems in the code.
Another reason that I like Hungarian notation is that I am much less likely to run into the situation where I have two variables that can only be distinguished by their casing. For me the probability of this happening is further decreased because I use camelCasing and PascalCasing for anything that is publicly exposed by my function, class or framework (more on that in future posts).
The only time that I will stray from Hungarian notation is in the case of constants. For constants I use the SCREAMING CAPS notation. I find that if I don't, I have difficulty visually identifying constants from variables when I'm reading code.
Hopefully this has given you some food for thought.
Consistency in anything you do is important. As developers we strive for consistency in our build processes, user interfaces, architectures and coding practices. The primary reason behind the attempts at all of this consistency is productivity. To quote the Framework Design Guidelines book (Section 1.1.7 Well-Designed Frameworks Are Consistent) by Cwalina and Abrams:
It (consistency) is one of the most important factors affecting productivity.
While Cwalina and Abrams tout consistency throughout their book, they do it with regards the benefits that it creates for the consumer (software developer) of a framework. I believe that the entire software development team (software developers, testers, maintenance programmers and framework consumers) can benefit from consistency.
Like the programming language itself, or the .NET framework, consistency in naming will abstract the details away from the programmer. If you know that all constructor parameters are named the same as the properties that they set, you will never hesitate or doubt. Good application of a standard will stop developers from having to make decisions when they are reading both their own code as well as code written by others.
In theory this lack of ambiguity will increase the productivity of all people involved. In practice the standard being enforced needs to be usable and readable. If I were to enforce a standard that said all integer variable names must consist of a single alpha character I would have a strong and reliable standard. The truth is that this standard, when left on it's own, does more harm by decreasing the readability of code than it does good. Every area that is regulated by standards has a balance point where readability and consistency does not become onerous or counter productive. Standards that find this balance point are the ones that are adopted by large groups with ease and go on to live long lives.
I'm going to gather the information in these posts from a couple of different sources. In addition to my own opinions and experiences I'm going to references the following two books. These are great tomes and I recommend them for purchase.
- Practical Guidelines and Best Practices for Microsoft Visual Basic and Visual C# Developers by Francesco Balena and Giuseppe Dimauro
- Framework Design Guidelines by Krzysztof Cwalina and Brad Abrams