Search This Blog

Programming Bias Comes From Experience

We all have our personal biases, especially when it comes to programming. There are eternal debates going on about what the best programming style is or why this programming language is great and that one sucks. We love to argue about static vs. dynamic, CamelCase vs. snake_case, and tabs vs. spaces. Most of these unwinnable arguments stem from personal biases. We argue because we feel so emotionally committed to our case, but there is no objectively right answer. (Well, maybe for tabs vs. spaces—the editor should handle it for you, of course.)

These personal biases develop because of things that have bitten us in the past. Behind every irrational, subjective programming opinion is a story about how a programmer got burned while using a particular language or trying out a new programming practice. That thing that the programmer grew to despise may not have been directly responsible for the failure, but it was there and it was noticed. Biases are born of cold, hard experience, and the frustration of having to deal with an issue that's getting in your way at a critical time is not soon forgotten.

That's not to say that the reasons for any of these programming biases are invalid. They are certainly real enough, but the opposing arguments stem from equally valid stories of their own. For every programmer that's been burned by static typing, there's one that's had their fair share of shocks from dynamic typing. In the end the opposing arguments tend to boil down to differences in experience and possibly personality, and it can be hard to tell those apart. Did a programmer have a bad experience because of a predisposition to a certain programming style, or did his preferred programming style develop from the string of experiences he had? Separating those causes and effects is difficult.

To give an example, I recently listened to a discussion about some of the things Jeff Atwood hates about C# on Stack Overflow Podcast #73 (~50 minutes in). To be clear, C# was Jeff's preferred language at the time when he was working on, and he claimed that you don't really know a language unless you can name at least five things you hate about it. Fair enough. I'm not sure I agree with that, but anyway, he could only come up with three for C#.

What struck me was that the things he came up with were things that have never bothered me about programming languages in the slightest. I couldn't believe he was so frustrated by them. His number one complaint was case sensitivity. It has never occurred to me that case sensitivity in a programming language was even an issue. I learned to program in Pascal and C, so to me, case sensitivity was The Way Things Were. I learned to be careful with capitalization when programming, the same way I'm careful when writing. Jeff used to program in VB, a case-insensitive language, so I can appreciate that he was used to not caring about case when programming and had to make an adjustment. At the same time, I can't see why it's that big of a deal.

So you see, we both have our personal biases when it comes to case sensitivity, and the real reason we differ is probably because of our early experiences with programming languages, not because one is intrinsically better than the other.

His second complaint was that C# didn't have dynamic background compilation. Today it does, so it's no longer an issue, but even at the time I don't remember it being particularly painful to have to compile before seeing where you made syntax errors. Actually, having to wait for the compiler to report syntax errors may have saved time in the long run because it forced me to develop good habits when writing code so that it would be as error-free as possible.

Things are certainly better now with IDEs, like Visual Studio and Eclipse, that can point out syntax errors as you type. I can't argue with that. Although, it would be nice if they held off a little bit instead of underlining stuff in a line before you've finished it. I'm not sure that I can program any faster because of background compilation, but it's nice to have the extra confidence that the code will compile right away.

Jeff's last complaint was that static and dynamic typing both have their strengths and weaknesses, and languages would really benefit from having features from both typing systems. Joel added that type inference can help static type systems a lot by adding some nice dynamic features. I definitely agree with them here. It's great to remove some of the line noise when creating objects, especially when the names are long. In C# for example,
VeryLongTypeNameForAnObject obj = new VeryLongTypeNameForAnObject();
becomes the slightly more tolerable
var obj = new VeryLongTypeNameForAnObject();
While type inference adds dynamic features to static typing, Jeff also wanted to see some static features added to dynamic typing so that it would be easier to find all uses of a variable in a program written in a dynamic language. In a statically typed language, the type system can disambiguate variables with the same name that are declared in different places, for the most part, so the IDE can rename variables and methods with a greater chance of success. Reflection can still muck up this operation, but it's generally safer in a statically typed language.

In my experience I have run into both of these issues with static and dynamic typing from time to time, but it's been rather rare. I tend to adapt to the language I'm using. When I write in a static language, I try to cater to static typing's strengths, and when I write in a dynamic language, I take advantage of dynamic typing's features. I can't say that I've come across many code bases where similar variable and method names were strewn across dozens of files, and if that is happening in a code base, there are bigger issues in play than what renaming is going to solve. But that's my experience, and if you had to deal with lots of far-reaching variables every day, you'll probably have different biases than I do.

I probably can't come up with too many things I hate about any given programming language I've used. Having to pass structs around in C is a bit of a nuisance, so a basic object-oriented system would be nice. Having a sane syntax in C++ would be great. Having a real object system in Python, so we wouldn't have to pass self into every class method, would be an improvement.

If I think about it, these complaints are all variations on a theme. What I struggle with the most in any language is how to best express what I want to in as succinct a way as possible. I hate verbosity. When a language makes me repeat myself or say things in ten lines when one should do, that's where I feel the most pain. In fact, if every language were as succinct and expressive as Ruby, I would be happy as a clam. It's too bad Ruby isn't fast enough to be used in more places.

We should be aware of our biases and where they come from so that we're not making decisions purely on gut reactions. I recognize that my bias in favor of Ruby comes from past experiences I've had with other languages. Programmers that are biased against Ruby have their own reasons. The same thing goes for many of the endless debates we have about languages, styles, practices, etc. For some of those topics, we may be able to make real measurements about what is better, but even in those cases it's probably not cut-and-dried. Some programmers will be more productive with one choice, and other programmers will do better with the opposing choice. For the rest of the topics, there may be no definitive right or wrong answer, only a field of options, and our past experiences may be the best guide we have for making a good choice.

No comments:

Post a Comment