Normally I stay away from most sites devoted to technology and discussions of it. But the other day I stumbled upon a story with the common lament that crops up periodically on such sites about how stupid other coders are. No real examples, just hearsay. In this story the examples led off with supposedly bad web sites that presented horrible (to them) entry fields. The story contained other examples of bad coding and the eventual eternal question: why can’t today’s coders write “good code,” good code being defined by the commenters in the story.
The same story linked to this old blog post from 2007 titled “Why Can’t Programmers.. Program?” (link: https://blog.codinghorror.com/why-cant-programmers-program/ ). This post is a good fifteen years old. A tremendous amount has changed since it was published. Existing programming languages have undergone fundamental evolution, new languages have come into existence, and programming fads have come and gone. To agree or disagree with this post at this point in history is a bit pointless. But it did provide something amusing for me to do; writing a FizzBuzz program in Python.
The rules for FizzBuzz according to the post are simple enough:
Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.
I made one important change such that I always print the number so I can check manually if the output is correct or not. Here’s the Python code. Yes, it’s absolutely without “elegance.” I have no use for elegant code, because that’s the code with the most bugs and the most difficult to maintain.
#!/usr/bin/env python3for i in range(1,101):if (i % 3 == 0) and (i % 5 == 0):print("FIZZBUZZ {}".format(i))elif (i % 3 == 0):print("FIZZ {}".format(i))elif (i % 5 == 0):print("BUZZ {}".format(i))else:print(" {}".format(i))
And here’s the last 11 lines of the output.
...FIZZBUZZ 90 91 92FIZZ 93 94BUZZ 95FIZZ 96 97 98FIZZ 99BUZZ 100
You’ll note in my implementation I print it all, the indicators along with each number. As I wrote earlier that’s so I can trace and check manually if the output is correct. There’s also another reason to do it this way.
In my deep past I’ve needed to hire folks to fill open admin spots. A test I’ve used in the past goes something like this:
- Write a simple program to out text, based on whatever criteria I use at the time.
- Pipe that text output to a file.
- Use Unix command line tools to search for certain patterns in the text from the file.
- Pipe the output generated in (1) into the same command line tools to search for the same patterns in (3).
I didn’t care what language they used as long as it produced the needed output. If I were to do this again, I’d adjust the test thus:
- Write a FizzBuzz program in Python and produce the output based on my given criteria.
- Pipe the output into a file.
- Use Unix command line tools to read the file and search for every instance of “FIZZ”, “BUZZ”, “FIZZBUZZ” and lines that don’t have either, and count the number of lines.
- Pipe the output generated by your FizzBuzz program into Unix command line tools to perform the same searches and counts in (3).
The purpose of all of this is to plumb their programming abilities a bit, as well as their abilities to problem solve on the command line. One solution to count the number of instances of FIZZ would be ./fizzbuzz.py | grep -w "FIZZ" | wc -l
. This yields a count of 27 lines. If you want to see exactly what the grep is producing then pipe grep’s output into wc -l
. The key for grepping the whole word is grep’s ‘-w’ command line switch. That works for the first three word searches. Searching just for blank lines (no words) is a bit more complex, with at least two general solutions. For extra credit, the candidate is required to save the grep output before counting the number of lines, which means they need to know how to use tee
.
I’d give a candidate no more than 30 minutes to do all of this. If they’re any good at all they’ll have it all done in far less time.
While I did say it was pointless to argue with a 2007 blog post, I will take a single exception. The was a comment in the 2007 blog post concerning recursion. A quote within that post called recursion as a way to solve a real problem. I do beg to differ. I come from a background in which recursion was to be avoided at all costs. Part of that comes from my initial background straight out of college (we’re talking mid-1970s here) where I was an embedded programmer. Iteration should be your first choice to solve any problem that supposedly calls for recursion.
I provide for your entertainment two implementations of everybody’s favorite recursion excuse, factorial, written using iteration, not recursion. First, a hoary old piece of Python I wrote about in a post on this blog back in 2014:
#!/usr/bin/env python3import sysdef fact(n):a = 1print( n, end="! = ")while n > 0:a, n = a * n, n - 1print(a)if __name__ == '__main__':if len(sys.argv) <= 1:print("Factorial calculator. Must call with at least one number as an argument.")print("Multiple numbers can be entered on the same line, as in '1 2 3'.")sys.exit()for i in range(1, len(sys.argv)):fact(int(sys.argv[i]))
And this is the same code re-written if you will for Julia:
#!/usr/bin/env juliafunction Factorial(n)a = BigInt(1)print(n, "! = ")while n > 0a, n = a * n, n - 1endprintln(a)endif (length(ARGS) > 0)for x in ARGSFactorial(parse(Int64,x))endelseprint("Factorial calculator. Must call with at least one number as an argument.")print("Multiple numbers can be entered on the same line, as in '1 2 3'.")end
They both produce the same output (although I leave it as an exercise to the reader to determine if it’s correct):
What I find interesting are both the strong similarities between Python and Julia, as well as their interesting differences. For example Python can handle big numbers transparently. For Julia, you have to declare a variable as a big number by initializing it with a BigInt (see line four in the second listing). Command line arguments are accessible directly in Julia, while Python requires you to import sys, and then work with those classes. I deal with both languages through Jupyter, but that’s a post for another time.
Neither one of these examples will win any awards. They’re both blindingly boring, and frankly, I strongly believe code should be written that’s boring. I hate “elegant” code. Boring is one trait of good code that allows it to be fixed if bugs occur or to allow extensions for new functionality.
Generally I’m old and retired and way past caring about the majority of this. But on this point I do care about the negative effect of the trolling critics who make those who are trying to produce better code and trying to improve their coding skills, nigh impossible to succeed. It’s the trolling critics that make it nigh impossible for all of us to have nice things, and to have good people produce those nice things.
You must be logged in to post a comment.