Years ago there used to be a contest to see who could produce the most obfuscated C code, and some of the results were dramatically unreadable. C was like that. You could really screw things up with the preprocessor in particular.
However, many of the newer features of C# offer an amazing opportunity to obfuscate code to. I was wondering if anyone had an opinion on finding the right balance between concision and clarity in code. Let me offer one example for discussion, the task of filling items into a ListView
. (Yes I know you can do it with data binding, but go with me here.)
The control is two column to be filled with an array of
struct Person
{
public string name;
public string address;
};
One, clear and simple way is this:
private void Fill(Person[] people)
{
foreach(Person person in people)
{
string[] columns = new string[2];
columns[0] = person.name;
columns[1] = person.address;
ListViewItem item = new ListViewItem(columns);
listView1.items.Add(item);
}
}
Clear and simple to understand.
I could also write it like this:
private void Fill(Person[] people)
{
foreach(Person person in people)
{
string[] columns = new string[] { person.name, person.address };
ListViewItem item = new ListViewItem(columns);
listView1.items.Add(item);
}
}
or even:
private void Fill(Person[] people)
{
foreach(var person in 开发者_如何学运维people) // Note use implicit typing here
{
listView1.items.Add(new ListViewItem(
new string[] { person.name, person.address }));
}
}
Finally, I could also write it like this:
private void Fill(Person[] people)
{
Array.ForEach(people, item =>
listView1.items.Add(new ListViewItem(
new string[] { person.name, person.address}));
}
Each uses various new features of the language to a greater or lesser extent. How do you find the balance between concision and clarity? Should we have an annual Obfuscated C# contest?
You know what's hard? Writing code that others can read and maintain. Any idiot can write code that compiles and is impossible to maintain.
Always favor maintainability: that's how you find the balance.
Edit:
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."
- Martin Fowler, Refactoring: Improving the Design of Existing Code
Thanks to roygbiv for finding the above quote. Apologies to Fowler for murdering his quote; I knew I'd read it before, I just couldn't remember where.
Stuffing everything into one line doesn't make it "obfuscated" -- it just makes you scroll a lot unnecessarily. It would still be trivial for anyone who knows C# to understand any of the examples you presented, and if you used linebreaks, none would really be much better or worse than the others.
Code for maximum readability, but:
Remember that superfluous verbosity and syntactic noise hurt readability. More conciseness can coincide with improved readability if the more concise notation allows you to express your intent more directly. For example, compare real lambda functions to simulating them with single-method interfaces.
Assume that other people who read your code are decent programmers and know the language you're working in. Don't assume a language lawyer level of knowledge, but assume a good working knowledge. Don't code to the lowest common denominator because, while it may make your code more maintainable by code monkeys, it will annoy both you and maintenance programmers who actually know what they're doing.
More specifically, example 1 has way too much syntactic noise for something so simple. Example 4 is very difficult for a human to parse. I'd say 2 and 3 are both pretty good, though in the case of example 3 I'd reformat it a little, just to make it easier for a human to parse all the function call nesting:
private void Fill(Person[] people)
{
foreach(var person in people)
{
listView1.items.Add(
new ListViewItem(
new string[] { person.name, person.address }
)
);
}
}
Now you have the best of both worlds: It can be easily parsed by humans and doesn't have any superfluous, unnecessarily verbose temporary variables.
Edit: I also think that using implicit variable typing, i.e. var
is fine most of the time. People write perfectly readable code in dynamic languages where implicit typing is the only kind of typing, and most of the time the formal types of your variables is a low-level detail that has little to do with the high-level intent of your code.
At least with respect to the example that you provide here, I don't really think Obfuscation rises as you proceed until you get to the last one. Even there, the only reason for any ambiguity is the presence of the Lambda and that just takes some getting used to. So, a newbie might have trouble with the last but shouldn't find the others unreadable in the way that the old wild C competition entries were unreadable.
The difference is that these C# examples are all at the same level of abstraction - the more concise examples just remove "fluff." In C, you have the opportunity for ambiguity due to A) arbitrarily renamed/aliased constructs and B) several levels of memory access bundled into one statement.
One the whole, then, you can right obscure code in ANY language but I don't think that C# is prone to it like C and, indeed, I think it is a clearer language than many - even when using some of the more advanced constructs.
C# and VB.NET languages were designed for more for clarity because they are operate at a higher level than C. C is programming close the metal so-to-speak. It's not possible by-design to write obfuscated C# like that of C.
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."
- Martin Fowler, Refactoring: Improving the Design of Existing Code
I do not find the example obfuscated.
First, the intent is so painfully clear, that a newbie is more probable to learn what a lambda does than not understanding the code. Which is the perfect place to use the more "advanced" techniques - where even someone that doesn't have a clue what they do understands what they "should" do.
Second, all of the above are not only not obfuscated, they are perfectly idiomatic C#. The last one arguably not so much because of the not so widely use Array.ForEach which most people (that I have worked with) would utilise LINQ.
精彩评论