Sometimes I have the odd dream that someday there will be programming language descriptivists in the same way that there are descriptive linguists -- but more so. They'll be the Unitarian Universalists of software development. Anything goes. It's all okay. Just get your job done and be happy.
That's not entirely wrong. The term "best practices" has a severe problem in that it implies that for any situation you can find a single best practice. The best practice often depends highly on your situation, and you often lack sufficient information to choose between several equally good options.
This is why we have so many programming languages and toolkits and libraries and design possibilities. This is why we refactor, and we iterate, and we try to learn from our experiences to continue building better software for our own purposes according to strong visions. We don't have to get it perfect, and there are many ways to accomplish the same thing. We just want to get it a little bit righter every time we make a change.
It's a false dilemma to say that all choices are equally good, however. If there's a secondary theme to all of my writing here, it's that some choices are bad.
Let me give you an example of what I want to call "the polar opposite of modern Perl". It's bad Perl. You can find plenty of examples of it on the Internet, but so many of them end up in search engines and then in copied and pasted code that well meaning novices copy and paste into their own programs, because it's just too hard to tell who's authoritative and who's right, and ... well, see for yourself: 2008 Winter Scripting Games Solution to Advanced Perl Event 1: Could I Get Your Phone Number?.
This code won't even compile if you use the Modern::Perl module -- and that's a feature of the module.
I particularly like some of the explanations of the code. It goes wrong on the first line:
Our script for Event 1 kicks off by creating a hash table (similar to a VBScript Dictionary object) named
%dictionary; that's what this line of code is for:
%dictionary = ();
In reality, that line of code does nothing. It doesn't declare a variable. It doesn't assign anything to the variable. It's effectively a no-op. It's useless, vestigial code that exists because... well, almost certainly it was copied and pasted from another program somewhere. It'll get copied and pasted further now, despite doing absolutely nothing, and more novice Perl programmers will get the wrong idea that this is how you work with variables in Perl because someone said so authoritatively -- never mind that the explanation is completely wrong.
(There's a naming quibble too. Almost no one calls hashes in Perl
dictionaries. We have a perfectly good name for them instead. It's "hash".
Of course, with the hash sigil and the keyed lookup syntax used to refer to
keys and values of the hash, it's obvious it's a hash, so this is like calling
a variable "variable" in another language. As the rest of the code uses this
variable as a mapping from numbers on a telephone pad to letters, a better name
%nums_to_letters, which at least gives some semblance of
the purpose of the variable, not its internal implementation.)
I can't afford to comment on every line of code here, but a few more groaners popped out at me even as I skimmed the code:
Once we have the hash table set up we use this chunk of code to open the text file C:\Scripts\WordList.txt, read the contents into an array named @arrWordList, and then close the file:
open (WordList, "C:\\Scripts\\WordList.txt"); @arrWordList = <WordList>; close (WordList);
This is another example of code that won't compile when used with
Modern::Perl. (It's difficult to blame the author of this code for that, however. Perl 5 arguably has the wrong default behavior... but the lack of error checking is disturbing. This is nothing compared to the sentence after the explanation of what this code does:
As you can see, it's easy enough to read the contents of a text file and store those contents in an array; however, as far as we know it's nowhere near that easy to search an array for a specified value (which we'll have to do to determine whether we've created a real word out of our phone number).
After demonstrating the use of a hash to look up values by key... yeah, I can't finish this sentence either. The example code instead joins all of the lines in the file -- one per word -- into a string and uses a regular expression to search the entire string for a word made from a phone number. This is not an esoteric problem. It's a frequently asked question about Perl, present in perlfaq4, the core Perl documentation, installed with every installation of Perl: How can I tell whether a certain element is contained in a list or array?
My gripe isn't that the regular expression search is inefficient (it is, but not as bad as it could be), nor that the code is clunky (it is), but this is a bad algorithm in any language. A better example is trivial to write in Perl, even for someone who's not an expert. Jan Dubois is a Perl expert, and the expert Perl solution to 2008 Winter Scripting Games Advanced Perl Event 1 is not only shorter and more correct, it also includes error checking, compile-time checking, and other robustness features. It's a little bit more complex and definitely more idiomatic, but it's correct and the explanation is also correct.
My gripe is this: someone deliberately published the novice version in 2008. It's bad code. It'd be bad code in any language. It's particularly bad Perl. Worst yet, it's bad code explained incorrectly.
That doesn't help anyone.