My code would suck less if the C# compiler raised an error anytime it detected the following:
- A button with no click handler.
- A click handler with no code.
- A parameter that is not used.
- Code that throws A '
NotImplementedException
'
- A
//TODO:
token.
- An
#if DEBUG
- A phrase that contains more than one dot, e.g.
Control.Parent.Parent.Parent.Controls[3].Controls["Accept"]
Q: Why do I want the compiler to be so mean?
A: It takes a tough man to make a tender chicken.
(attributed to Purdue, quoted in 'Worse Is Better')
No, the common thread here is these are pitfalls common to a top-down, (or an outside-in) design approach.
As you move top-down, (or from front to back), you throw off "branches" -- kind of last strands -- that you need to back-track to complete later. I want the compiler to help me find those branches. (Tests are a poor substitute)
In his 2005 classic 'Does Visual Studio Rot the Mind?' Charles Petzold showed how intellisense-and-friends encourage bottom-up programming.
These are some little features that could help out the die hard top-down coders.
Details...
"A button with no click handler"
Why does a button exist? Is it just to look good?
No! Buttons are for clicking!
A button with no click handler is a fail.
And a click handler with no code is a fail as well.
What does the user expect when you click a button?
Unless this is that Early Internet Phenomenom known as The Really Big Button That Doesn't Do Anything, a user expects *something* from a button.
Why would you check that in? What good can possible come from letting do-nothing buttons end up in the hands of unsuspecting users?
The world of static code analysis has gone very far -- but does it stop and help us avoid this sort of psychological torture?
(This same concept may be true for many other objects that raise events. The object's author might be able to indicate "There's really no point using this thing unless you handle the following event(s).")
A parameter that is not used.
Unused variables raise a warning, but unused parameters don't.
This is a little bit good, but it's a little bit bad as well.
Here's an example where the unused parameter is clearly a bug:
private void CopyFile(string sourcefileName,
string targetFileName,
bool overwrite)
{
System.IO.File.Copy(sourcefileName, targetFileName);
}
Oops!
The programmer forgot all about the 'overwrite' parameter!
I consider that a pretty clear error.
But consider our click handler for a moment:
private void Button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello");
}
Neither parameter is used. But if we were to call this an error, a hell of a lot of code that's shipping today would fail.
Some design changes could alleviate the dilemma -- I'll leave the consideration of possible solutions as an exercise for the interested reader. The goal is to avoid busy work, not create it.
Code that throws A 'NotImplementedException
', and //TODO:
token, #if DEBUG
conditions and everyone from System.Diagnostics.Debug
Not Implemented Exceptions are excellent stuff.
But your goal is always to eradicate them, right? They're a kind of hardcoded place holder. A warning ought to suffice. (You treat warnings as errors, most of the time, right?)
I put //TODO:
tokens and #if DEBUG
conditions in the same category. They're very handy scaffolding or place holders as you crank out your code -- but they're not supposed to remain indefinitely. A warning would be nice. Maybe Debug.WriteLine
and its friends should fall into the same category.
A phrase that contains more than one dot, e.g. Control.Parent.Parent.Parent.Controls[3].Controls["Accept"]
Why would a compiler let you get away with this kind of monstrosity?
It would be quicker to just replace that whole line with "throw new NullReferenceException()
". The effect would be the same.
My point here is that this kind of implementation of the house of cards anti-pattern is easy for static analysis tools to pick up.
I know that there are existing static analysis and code grepping tools that can be used for some of these cases, but they tend to run 'after the fact', outside the tight code-compile loop. Worse: they tend to produce a lot of noise and take a lot of care and feeding.
StyleCop is the worst 'busy work' generator I've seen. (If only they'd finished the job and had it auto-correct many of the problems it finds... instead, like '100% code coverage' it's a kind of training tool for Coder's OCD.)
Alrighty -- that's all I've got for now, though if I keep my eyes open, I bet I'll spot some more.