Comments should tell you what the code does not, not necessarily deliniated by WHY, HOW, or WHAT. If you have good names and have well delineated functions, it is quite possible that the code can tell you exactly what is going on. For example:
List<LightMap> maps = makeLightmaps(receivingModels);
TrianglePartitioner partition = new Octree(castingTriangles);
List<Photon> photons = firePhotons(lights, partition);
if (photons.Count > 0)
PhotonPartitioner photonMap = new KDTree(photons);
gatherPhotons(maps, photonMap, partition, lights);
This code really does not need comments. The function and type names make it easy to understand.
Sometimes, however, it can be difficult or impossible to really make fluent code like the above. For example, the next code snippet is for finding a statistically random point on a sphere. The math is pretty opaque, so a comment with a link to the explanation is to help tell HOW it works. This can be wrapped in a function to tell WHAT it does without needing a comment if needed more than once, otherwise the link title also helps in that department.
double randomA = localGenerator.NextDouble();
double randomB = localGenerator.NextDouble();
double theta = 2 * Math.PI * randomA;
double phi = Math.Acos(2 * randomB - 1);
Vector3 randomDirection = new Vector3(Settings.ambientRayLength * (float)(Math.Cos(theta) * Math.Sin(phi)),
Settings.ambientRayLength * (float)(Math.Sin(theta) * Math.Sin(phi)),
Settings.ambientRayLength * (float)Math.Cos(phi));
Another example of when comments tell you what the code does not is for explaining a decision. In the next example, the code does not lock a non-thread-local variable inside a threaded piece of code. There is a reason for this and the comment explains WHY. Without the comment, it might be considered a bug, or just not be even noticed.
Random random = new Random();
Parallel.For(0, maxPhotons, delegate(int photonIndex, ParallelLoopState state)
//I don't actually care if this random number is unique between threads, threadsafty is not that big of a deal
// in this case and locking the random object could cause a lot of lock contention
while (random.NextDouble() > reflectProbability)
It could, perhaps, be improved to say why the random object is not created inside the parallel loop in the first place. If there is no reason, it could also make someone come along and realize that the whole idea is stupid and is a good place for refactoring.