Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obfuscated C# Code - What is the balance between concision and clarity?

Tags:

readability

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?

like image 379
Fred Thomas Avatar asked Jan 23 '10 21:01

Fred Thomas


3 Answers

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.

like image 164
Esteban Araya Avatar answered Oct 31 '22 13:10

Esteban Araya


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.

like image 6
mqp Avatar answered Oct 31 '22 13:10

mqp


Code for maximum readability, but:

  1. 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.

  2. 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.

like image 2
dsimcha Avatar answered Oct 31 '22 13:10

dsimcha