Style guidelines

Syntax

Indent blocks two spaces. Make sure your editor uses spaces only, no tabs.

  1. Maybe... It looks like at least the Microsoft standard is to put braces on their own lines, and to leave them out for single-line blocks. Should we consider going with this style instead?
  2. Or... Use the same bracing style as was used in the Java code branch. Braces are required around every block, even single-line ones. Opening braces go at the end of function signatures, ifs, try/catch statements, etc.

Don't put a space before or after left parentheses, except for after a language keyword like if or for. Put one space before left parentheses in that case.

Try to minimize the use of parentheses. You can rely on operator precedence and associativity to disambiguate most expressions, so only use parentheses if you need to override the default precedence/associativity rules. For example, || has lower precedence than &&, which has lower precedence than relational operators like == and <=, which in turn have lower precedence than arithmetic operators. So writing

if (index >= 0 && index < array.Count - 1 || array.isEmpty)

is preferable to

if (((index >= 0) && (index < array.Count - 1)) || (array.isEmpty))

Here's an example demonstrating these guidelines:

try
{
  File   file = new File("sample.txt");
  String line = null;

  while ((line = file.readLine()) != null)
    output.writeLine(line);
}
catch (IOException exception)
{
}
finally
{
}

C# niceties

C# has a few syntactic niceties over Java. Instead of getXXX and setXXX methods use properties, like so:

public int Length {
  get { return this.length;  }
  set { this.length = value; }
}

C# also has enumerations, a feature Java inexplicably left out. For a list of constants, don't create a series of static final int variables, or whatever. Instead, do this:

public enum XPathTokenType
{
  /// <summary>Left parenthesis '('.</summary>
  LeftParenthesis,
  /// <summary>Right parenthesis ')'.</summary>
  RightParenthesis,
  /// <summary>Left square bracket '['.</summary>
  LeftBracket,
  /// <summary>Right square bracket ']'.</summary>
  RightBracket,
  /// <summary>Current node '.'.</summary>
  Dot,
  /// <summary>Parent node '..'.</summary>
  DotDot,
  /// <summary>Attribute sign '@'.</summary>
  AttributeSign,
  /// <summary>Comma ','.</summary>
  Comma,
  /// <summary>Axis separator '::'.</summary>
  ColonColon,

  ...
}

Naming conventions

C# has a slightly different naming convention from that of Java or C++. In C#, all public members should be capitalized—even functions and variables. Private members are distinguished by having names in lower case.

As a rule, don't abbreviate words in names. Always spell out every word completely, even if the name is long.

Boolean variables/properties/functions should usually begin with is or something similar, such as isEmpty. This is a standard naming convention to make code read more like English, and is an easy way to distinguish booleans from other types.

Otherwise, avoid tagging variables with prefixes/suffixes indicating their type. For array or list variables, instead of adding "list" or "array" at the end of the variable name, make it plural. So elements is better than elementList.

XML Documentation

Please document every class, method, property, and variable—even private ones! Learn and use the C# XML documentation format. It's basically like Javadoc, except everything's marked up with XML tags. The MSDN Library has full documentation of all the tags. Visual Studio will generate a documentation template when you start an XML comment, automatically adding tags for each parameter to a function, for example.

There are several reasons why this is very important to do:

  1. If you get into the habit of commenting code as you write it, it's an easy CMMI practice to follow.
  2. Just like Javadoc, we can dump these comments to HTML pages, getting full API documentation for "free".
  3. Visual Studio understands these comments. It will popup tooltips when you hover over variables/methods/etc. that have been documented.
  4. If you tag everything well, the compiler will warn you when comments get out of date, like if you rename a variable but don't update the comment.

It's really important to tag every reference to a variable/function/class/whatever in your comments. You can do this by adding the cref attribute to any tag, or by using the <paramref/> tag for parameter names. If you do that, Visual Studio will create a link for the name, and will also be able to warn you if you change that name later and forget to update the comment.

Visual Studio has an option you can enable to warn you about uncommented items. Please turn this on! It's always tempting to think we'll go back later after you've finished coding to write all the comments you need to, but we usually never find time to go back and do it. Turning on this option will keep us from slacking off since the warnings will hopefully nag us into commenting sooner rather than later.

Quirks

The documentation for XML comments is a bit inadequate. In lieu of any official guidelines, let's follow these:

Formatting

The default style of writing tags on separate lines like

/// <summary>
/// The length of the array.
/// </summary>

seems excessively wasteful of vertical space. I think it looks better to put the text on the same line as the tag, like people normally do with <p/> paragraphs in HTML.

/// <summary>Validates the given XML document and returns an <see cref=
/// "XmlDocument">XmlDocument</c> containing the document.</summary>
///
/// <param name="xmlReader">A reader referencing the XML document to validate.
/// </param>
/// <param name="grammarNamespace">The namespace for grammar elements.</param>
///
/// <returns>An <c cref="XmlDocument">XmlDocument</c> containing the document.
/// </returns>
///
/// <exception cref="XmlSchemaException">Thrown if the document does not
/// validate against the schema.</exception>
/// <exception cref="XmlException">Thrown if the document is invalid for a
/// reason not expressed in the schema.</exception>
private XmlDocument loadDocument(XmlReader xmlReader, string grammarNamespace)
{
  ...
}

Assertions and Unit Testing

Assertions

Assertions are a great way to check conditions during run-time that should always be true—things like parameter values being correct, or verying that a variable has the correct value in a complex piece of code.

You should add assertions wherever possible, usually to verify that a function's parameters are correct. Use the Debug and Trace classes in System.Diagnostics for this purpose. The only difference between the two is that Debug is enabled only for debug builds, whereas Trace is enabled for both debug and release builds.

using System.Diagnostics;

Boolean IsValidXPath(String xpath)
{
  Debug.Assert(xpath != null);
  Debug.Assert(xpath.Length > 0);

  ...
}

Do not use assertions to check for valid user input, or other conditions like that which can fail during the correct operation of the program. Assertions should only be used to verify conditions that absolutely must be true no matter what. If you need to verify things that do not indicate coding errors, such as a file not opening or an input file having errors, throw an exception instead.

Unit Testing

Unit testing involves adding tests for each public class and method to check that they are fully functional. We will be using the NUnit package to do our unit testing.

You should add as many unit tests as you think are necessary for each public method in the program. They should verify that the method does what it is supposed to do. Unit tests are mainly useful during refactoring, when rewriting and reorganizing large chunks of code, to verify that the new code still works.

Unit tests are fully automated, so always run the full unit testing suite after compilation to ensure that nothing is broken.

Important: Whenever you unearth a bug and fix it, document the bug by adding a unit test to exercise that bug. Oftentimes old code has been written to avoid many non-obvious bugs; if those bugs are expressed as unit tests, then we will guarantee that nobody ever accidentally reintroduces that bug again later on when "fixing" old code.

Exceptions

Specific exceptions

Exceptions should be used extensively for error-handling whenever possible. Always use the most specific exception possible. It's a bit cumbersome, but you should always try to create a custom exception class for each type of error. In the long run, the payoff is large.

Along with this, don't ever write catch (Exception exception). That's too large of a net to cast and will likely catch exceptions you hadn't planned on catching, hiding errors. It also kills exception propagation, preventing exceptions from bubbling up properly.

Instead, catch a more specific exception. There's nothing wrong with having multiple successive catch blocks to catch each type of exception you are able to handle.

Catching exceptions

If we do this properly, then we can observe the most important tenet of exception handling: only catch an exception if you can actually deal with it at that point. The reason exceptions are better than old-style error codes is that you don't have to handle errors immediately. You can let somebody higher up in the call chain handle an error if you don't have any particular recourse.

So instead of catching an exception, logging the stack trace, and moving on, just let the exception propagate upwards. It's a good idea to wrap the exception if you can, but you should rethrow it unless you are able to fix whatever problem caused the exception.

Miscellaneous

Distinguish between externally visible classes and internal FormFaces ones. Use internal for most classes; use public only for classes that are to be part of the external FormFaces API.

(This does not apply to methods; if the class is already internal, you should just make the methods public. You'd only need to make a method internal if it belongs to a public class but should only be called from within FormFaces.)

(Maybe) Always qualify references to class variables with this. It helps to distinguish between local variables and class variables in function bodies.

Prefer the uppercase forms of built-in classes to lowercase ones—Boolean instead of bool, Object instead of object, etc. However, stick with int instead of Int32.

Edit this page | As of September 26, 2004 at 11:18pm