We prefer code be written in pairs. For remote pair programming, look into TightVNC (or any other VNC) and Skype. If you're on a Mac running OS X, also consider SubEthaEdit. At least one of the core developers hacks bugreport on a Mac and SubEthaEdit is well-suited to remote pair programming. Code without unit tests that fully cover changes will not be accepted. To facilitate this, we highly recommend doing unit test first test-driven development (TDD). For help with remote pairing and/or TDD, ask on the mailing list and see if and when one of the core developers is available to help.
This document is broken up into two sets of guidelines, but they are all important. The distinction is more fuzzy than absolute, and exists primarily to identify which guidelines may be simple enough to implement in your editor (style guidelines) and which require some thought or reflection (design guidelines). Note, however, that style and design are two interdependent elements of a whole craft, not strictly orthogonal pieces. Follow as many of these guidelines as often as you can. Work to improve. Suggest your own guidelines so we can learn from you.
get{}/set{}
blocks. [Matt]
[Test]
[ExpectedException(typeof(ArgumentException))]
public void InitialValue() { ... }
System.Collections.Generic
. Anything that downcasts to object at some point should be avoided. [Matt]int
, byte
, char
, string
, etc.) -- use the FCL type names instead (Int32
, Byte
, Char
, String
, etc). [CLR via C#, p119]as
to cast instead of the usual cast operator. [CLR via C#, p101-102]
class Base { public virtual ToHtml() { ... } } class Css : Base { public sealed override ToHtml() { ... } }
this
keyword unless absolutely necessary.#region
directives. They hide the size and complexity of classes and methods, and therefore the need to refactor. That disadvantage outweights the extremely minor advantages. [Matt]
public class FooTests
{
[Test]
public void FooWithNoBarsTest() { ... }
[Test]
public void FooWithOneBarTest() { ... }
[Test]
public void FooWithTwoBarsTest() { ... }
}
We know it's a Test and we know it relates to Foo. With duplication removed:
public class FooTests
{
[Test]
public void WithNoBars() { ... }
[Test]
public void WithOneBar() { ... }
[Test]
public void WithTwoBars() { ... }
}
String.Empty
, empty array, empty array list, 0, etc. It expresses the intent of how the class handles invalid data and makes for less and easier debugging. [Matt]throw new ArgumentException(string parameterName, string description)
.lock() {}
instead of Monitor.Enter()/try/finally/Monitor.Exit()
. It compiles down to the same IL anyway. [Matt]Console.WriteLine()
, or unused classes/variables/methods/properties in the code. If you need it later, reach back in the source control history or make a wiki/blog entry. [Matt]Assert
for that condition/output in a test. [Matt]Assert.IsTrue()/IsFalse()
has crappy output in the NUnit runners that requires debugging to figure out why things failed. Make sure there isn't a better Assert
method in StringAssert
or elsewhere before using IsTrue()/IsFalse()
. [Matt]ref
or out
parameters. These shortcuts may work around the fact that the code is telling you that it wants a new type. On top of that, they make it difficult to debug things. [Matt]Stream
instead of FileStream
, or IEnumerable
instead of List
or IList
. [CLR via C#, p210-211]FileStream
instead of Stream
, or IList
instead of IEnumerable
. [CLR via C#, p211-212]A
can request a service (call a method) of an object instance B
, but object A
cannot "reach through" object B
to access yet another object to request its services. Doing so would mean that object A
implicitly requires greater knowledge of object B
's internal structure. Instead, B
's class should be modified if necessary so that object A
can simply make the request directly of object B
, and then let object B
propagate the request to any relevant subcomponents. If the Law is followed, only object B
knows its internal structure. [Dan]