Wednesday, June 17, 2009

javadoc @return not that helpful

A co-worker pointed this out to me after I suggested he "fix" his javadocs by using @return:

http://publicobject.com/2008/02/java-minutiae-return.html


So to ensure you have useful information in the JavaDoc method summary table, prefer a description of what your method returns over using @return, particularly if you're not providing any other descriptive text. In case you're wondering, this doesn't cost you anything in Eclipse... the auto-complete popup shows both the descriptive text and the @return text.

Friday, February 6, 2009

Don't "Use the language you know best."

Somewhere in the intertubes I came across an interesting response to my post on using Python and Ruby for interviews. The author stated rather categorically that for an interview you should simply use the language you know best...well of course...of COURSE... right? Wrong.

Programming languages are tools of the trade. A well-rounded programmer knows a handful of languages reasonably well. If you're familiar enough with two or three languages to Get Things Done, then I suggest you approach your interview problem the same way you approach your everyday job: examine the problem, look at the tools you have available, and then pick the tool that you can use to solve the problem fastest. For those of you with only one language in your tool belt, your choices will be limited.

Because we often work on a single codebase for months at a time, it's hard to become really good at lots of programming languages. But that's OK, you don't need to be. When a tool is well suited for a problem, it doesn't take a grand master to get the job done. Do you really need to be a wizard to remember how to use grep? Is working with python lists or ruby code blocks that hard to remember? Maybe you don't remember how to write a for loop in Awk. Who cares? When you need to select the 4th column of comma-delimited text, but only if it's > 0, Awk is Brain Dead Simple. Good tools lend themselves to the task at hand so well that even an amateur can get it done.

So learn enough about the tools you don't already know to understand what they were designed to do, and the next time you see a screw don't reach for a hammer. Learn Java, Ruby or Python, and Bash at the very least. Learn a handful of common unix commands. Yes, you should carefully study the language you use every day. That's your Chef's knife. Now don't be an idiot when faced with a problem for which it's ill-suited. If it feels clumsy, you're probably not using the right tool for the job. Put down the C# or Java and pick up the python, ruby, awk, sed, tr, cut, perl, xargs, paste, bash, etc. If your interviewers want to see you flex your Java muscles they'll let you know.

Mastering a single language is a small part of developing your craft, and sticking to that language no matter what is a rookie mistake. Don't fall for it.

Friday, January 23, 2009

Use Python or Ruby for your next job interview

You're at a job interview at some big software company and you need to write code that...oh I don't know... reverses the order of words in a string.

What language would you use for the job? Sure, you spend all day coding in Java, but you also work on enterprise software that runs on app servers, parses XML, connects to relational databases, and does other typical enterprisey stuff. You design complicated class hierarchies and testing frameworks. Your dependencies are all injected, control all inverted. Your frameworks and APIs are legendary.

But here you are...it's 10 am and you have a whiteboard, some markers, and some simple string manipulation to do (when was the last time you had to manipulate strings anyway?). You're nervous, the clock's ticking, and now that you've got the O(N) solution in your head, you need to express it in working, readable code... and fast!

So you break out your best Java, and suddenly the language presents you with a number of distracting questions. Do you return an array of Strings or a String of words? Do you use a List or an array (and possibly arraycopy)? Since it won't technically run without one, do you bother defining a class? Is the method public, private, protected, or default? You know static is evil, but should you just make it static for the sake of the interview?

Here's how I envision a typical* interview for an entry-level position...

Java Jimmy

JJ: "OK, I think I have a working solution in my head, I'll just write it up as a method...I'll have it take a String and return a String, and I'll call it reverseWords."

public String reverseWords(String words) {

JJ: "Oh, wait, is it ok that this isn't in a class? I know it won't run outside of a class, so maybe I should play it safe."

class StringUtil {
public String reverseWords(String words) {

Me: "Hey, don't worry about that, a simple method is fine."
JJ: "And I can skip main?"
Me: "Yes, that's fine, this is just a utility method somewhere."
JJ: "OK, I should probably make it static, even though static is evil."

public static String reverseWords(String words) {

JJ: "Do you care about being super efficient? I could use String concatenation or StringBuilder."
Me: "Whatever you prefer."
JJ: "Ok, since using StringBuilder.reverse is probably cheating, I'll use Strings and an index."

public static String reverseWords(String words) {
String reverse = "";
for (int i = words.length()-1; i>=0; i--) {
reverse += words.charAt(i);
}
// now reverse words...

JJ: "Should I use StringTokenizer or regular expressions?"
Me: "Whatever you prefer."
JJ: "Hm, OK, StringTokenizer is pretty easy, so I'll use that. Do you want me to write the import statement?"
Me: "No, that's fine."
JJ: "Great."

String result = "";
StringTokenizer st = new StringTokenizer(reverse);
while (st.hasMoreTokens()) {
String word = st.nextToken();
for (int i = word.length()-1; i>=0; i--) {
result += word.charAt(i);
}
if (st.hasMoreTokens()) {
result += " ";
}
}
return result;
}

Me: "Great, now how does it perform?"
JJ: "Oh, well jeez, Strings are immutable, and I'm using string concatenation, so I should probably use StringBuilder...I'd never actually write it this way in production."
Me: "Sure, go for it."

public static String reverseWords(String words) {
String reverse = new StringBuilder(words).reverse()
.toString();

// now reverse words...
StringBuilder result = new StringBuilder();

StringTokenizer st = new StringTokenizer(
reverse.toString());

while (st.hasMoreTokens()) {
String word = st.nextToken();
for (int i = word.length()-1; i>=0; i--) {
result.append(word.charAt(i));
}
if (st.hasMoreTokens()) {
result.append(" ");
}
}
return result.toString();
}

JJ: "How's that?"
Me: "OK, great, now that you're warmed up, let's get to the main question."
JJ (inner monologue): "Holy crap, I only have 25 minutes left!"


Peter Python

PP: "OK, I'll define a simple method and use Python lists freely."

def reverse_words(words):
result = []
words = words[::-1]
for word in words.split():
result.append(word[::-1])
return ' '.join(result)

Me: "Great, can you make it even shorter?"
PP: "Oh! Of course!"

def reverse_words(words):
return ' '.join(words.split()[::-1])
Me: "And how does it perform?"
PP: "O(N), assuming that reverse, split, and join are all O(N), and why wouldn't they be?"
Me: "Nice work."

Rebecca Ruby

RR: "Oh fun! This'll be easy to code up in Ruby, is that ok?"
Me: "Sure, whatever you prefer."
RR: "OK, let's see, I want to reverse the words, split them, reverse each item, and then join them again."

def reverse_words(words)
words.reverse.split.map{|w| w.reverse}.join(' ')
end

RR: "I think I'm done. I hope I did it right. I just used some pretty basic ruby."
Me: "Wow, that was fast. What's the runtime?"
RR: "Assuming that reverse, split, and map are O(N) (and why shouldn't they be), this is O(N)."

Here are a few other things you'll have an easier time doing on your interview with Python or Ruby:
  • Easily work with typical interview datatypes like strings, numbers, and lists.
  • Slice and dice collections and strings
  • Read to and from files
  • Dynamically grow or shrink lists (it's amazing how often you actually need this in an interview)
  • Create and manipulate hashtables (also comes up a lot in interviews)
And if the interview's at a workstation you can easily:
  • Generate test data
  • Iterate over your solution and profile how long it takes for various datasets
  • Just run your program. You don't need to compile it, you don't need "public static void main", you don't need classes, and you don't need to explain how you're using static even though you know it's a Bad Idea. And you don't need to choose between complicated command-line classpaths and big IDEs.
Give Python or Ruby a try at your next interview. And if you don't know either, what are you waiting for?

Tuesday, January 13, 2009

Teach students to write open source software

A few years ago I proposed a new course at NYU: Production Quality Software. It requires students to complete weekly assignments, conduct code reviews, write unit tests, think carefully about API design, and repeatedly iterate on their solutions based on peer feedback. Even the submission process was reworked with real software engineering practices in mind...every student gets a Subversion repository. There's no reason to use email when svn export works just fine. (And why not teach them another tool?)

To drive home the idea that sharing code is a Good Thing, and to teach them the joys and perils of open source, the final project is a contribution to an open source project of their choice.

Fall 2008 marked the third time I've taught this course. Student reviews came back positive, and the list of open source project contributions continues to grow:
If you teach software engineering, consider asking your students to share code with each other (after you've collected it) and to work on open source. Give them the satisfaction of knowing that their work is not an academic exercise, but a real contribution to a living breathing product.

If you're a student, consider doing code reviews with your peers once your assignment is over. A session with half a dozen other programmers will surely yield more suggestions than your TA or Professor (you're probably the 42nd implementation they're reading). Make it a regular habit and you'll find your code gets better with every assignment.

Tuesday, October 21, 2008

Doodlebyte has moved!

I will publish all new doodlebyte posts here on blogspot. I'll keep the old posts at cs.nyu.edu/~michaels/blog for now, but make sure to update your rss feeds.