Wednesday, July 1, 2009

Review: Rapid Development

Rapid Development CoverI just finished reading Steve McConnell's Rapid Development: Taming Wild Software Schedules. Well, many times it was not exactly "reading", more like "page-skipping". Obvious. Obvious. Obvious. But every time I thought I knew what was coming there was something unexpected hidden inside this big recapitulation of Fred Brook's findings. With big hard data pictures on the border. And then I'm horrified that I can relate to most of what is written, and that nothing's really new to me any more. Even if I didn't expect to read it from McConnell.

So the excitement of the days when I wrote stuff like Do You Understand XP? is gone. Rapid Development is a good book that reviews every practice it preaches with a critical eye, but I'm not overly excited. Yes, I learned, again, that many so-called Agile practices are known for a long time. But hey, I knew that after reading the Mythical Man Month. Excitement is hard to find in books these days. If I only could find one of those thought-provoking books, that rips your universe apart.

Saturday, June 6, 2009

All Programmers Are Code Narcissists

01001101011110010010000001100011011011110110010001100101
00100000011100100111010101101100011001010111101000100001

I finally discovered the truth about why developers rather rewrite a 1MLOC project from scratch than trying to understand a fellow programmer's code:

We're all code narcissists!

And the reason for that can easily deducted in a tiny logical chain:
(The best code is easy to understand) ^ (I can understand my own code the easiest, duh!)
=> (My own code is the best code)


Unfortunately this is only true for me, or perfect clones of myself. Which rules out everybody else I work with. Which reminds me... What was the reason that programming is done in teams?

Sunday, February 8, 2009

Test Everything That Could Possibly Break - A Guide To Better Testing

Joe: "Writing this test will make sure that we find bugs quicker. It will let us change the code without breaking anything and it will help us to write decoupled code."
Jim: "Maintaining this test will be a nightmare. It is tightly coupled to the class we're writing and we cannot change anything without changing the test. It will be a pain."
Joe: "How do you know?"
Jim: "Well, how do you know?"
Joe: "I have 20 years of experience not writing unit tests."

So what?
When I'm writing new code I am never sure whether I test enough, or if my tests are on the right level of abstraction. For complicated core functionality of a distributed system this is a no-brainer - I use TDD, which by the very definition gives me 100% code coverage, and add some nice integration and acceptance tests. But there are a myriad of cases where going forward in the baby-step TDD way seems a waste of time, and it would really help me to find some sensible rules to apply.

The simplest and best rule I have found so far is an idea from Extreme Programming:
Test Everything That Could Possibly Break

Unfortunately this rule is not as simple as it looks. My approach to that is the good old mantra of try-measure-adapt, where try means to just do whatever a randomly selected guy thinks is the new cool-aid, measure means to listen to that whimsical thoughts my brain produces while doing it and adapt means to look at the results and change my behavior.

So here's my guide to better testing, from the beginner to the professional level:

Beginner: Do some unimportant project by following the description of TDD step-by-step. Don't waste your employers money with that if you don't have any idea of how to do it - the first time you use it will be a disaster. Writing yet another Sudoku solver in your favorite programming language might be a cool idea.
The important part is that you don't have an idea of what "test everything that could possibly break" means, so your best bet is to assume everything might break. Even those getters and setters over there. Remember that you're not allowed to rant about made-up scenarios of why too many tests might be bad if you have never experienced what it means to maintain a program with too many tests. Do that first and come back later and read on.

Advanced: So you already have some experience doing TDD and know how it feels to write all those little unit tests. You got some feedback on when those tests caught a stupid bug that would have taken an hour to find if you hadn't written the test. You now know what the impact of unit tests on your ability to do refactorings is. Now go and break the rules by various degrees. Try to be less exhaustive with your tests and bundle your baby steps into bigger units of work. See how that affects your ability to find bugs. Test your assumptions and be aware of when they break. When you find a new bug that takes some hours to debug, think about what kind of test would have helped you find it quicker and write those tests from now on.

Expert: If I were an expert I could probably tell you more about what to do in that case. I still hope that repeating the advanced guidelines will finally make me as wise as Joel and Jeff in their discussions or Jay Fields when he writes about developer tests. Perhaps listening to those guys will enlighten you. You could even take a look at the very interesting discussion of the idea to test everything that could possibly break.

In a nutshell:

  • Start by testing everything, even if it looks stupid (don't do it at work).

  • Do slightly bigger steps and see what happens.

  • Adapt whenever you experience a situation in which different behavior would have made more sense.

Monday, December 22, 2008

Leaving the Comfort Zone

A week ago I held my first talk since university. It was the first talk in my life I held in English, and I was scared like hell. It felt like living through those exam days back at school all over again - just that this time I thought I'm old enough to realize that it'll all be okay. I'm obviously not.

I acted just like I did back in school. Or worse. I waited for the last possible moment before I started preparing the talk. When I finally started with the slides, a little perfectionist devil Manuel sat down leisurely on my left shoulder, telling me that this crap is just not up to my own standards. I worked long hours the night before the big day, and woke up early just to be able to rehearse the whole play before entering the stage.

Of course everything worked out just fine. Well, besides me saying basic-a-lly all the time. So why was I so freaked out? Well, I was obviously leaving my comfort zone.

Now the interesting thing beneath all that personal drama I'm ranting about is that I suddenly realized for how long I did not really step out of my safe little comfort zone. Granted, applying at Google is not the most un-stressful experience I ever had. And obviously starting a new job with all those bright people around me did not exactly make me fell warm and cozy.

But at that very moment I stood there, my peers gazing absent-mindedly into their laptops, my hands slightly sweating, I suddenly realized that ever since I started working I was doing everything exactly in the way I was most comfortable with. And that was kind of a shock.

Of course after giving the talk I felt great. I had known that in advance, but I realized that without being nudged enough I'd probably have tried to wiggle out somehow.

Lessons learned:

  1. It's easier to step out of the comfort zone when somebody kicks your ass.

  2. It's a long way from leaving your comfort zone once to real change.

  3. I must learn how to leave my comfort zone on my own.



Do you know tricks that make it easier to leave the comfort zone?

Saturday, June 7, 2008

One Day In My Life As A Googler

Disclaimer: this is a personal entry. Which means that if you are here for technical revelations or to gather super secret information about Google, go away, or I'll bore you to death. Seriously. Don't tell me I didn't warn you.

6:00 am: The iPod station starts playing and lifts me gently from the land of dreams.
Stanford"... Don't run away the time is now the place is here ..."
Sasha's swinging voice finally makes me cautiously open my eyes: another sunny day in Mountain View. The weather gadget on my iPod informs me that the temperature is currently 11 degree Celsuis, probably rising to a comfortable 21 throughout the day. I realize that I still don't know how to convert Celsius to Farenheit without accessing the Internet.

6:40 am: Armed with a gbike and a helmet I finally leave the apartment, trying to get warmed up for my workout on the 3 mile ride to work. While I pass the sporadic early jogger I can see the first rays of sunlight painting the landscape in warm colors. Pushing the pedals gets my pulse up to 150. Sweet.

6:55 am: The gym is wonderfully empty at this time of the day. With just a handful of Googlers around me I enjoy a quite workout. Today I'm torturing my upper body.

7:45 am: I end my workout with an easy 50 minute run along Mountain View's beautiful shoreline.Jogging Track Squirrels pass my way while two chatting women overtake me. I realize that I've got a long way to go before I will become a decent runner. Well, at least I can program computers.

8:50 am: Breakfast time. I get myself some freshly made scrambled eggs with crispy bacon, two chocolate croissants, some healthy orange juice and a steaming cup of coffee. Throughout the next view minutes some of my colleagues from the build tools team arrive, and a discussion about espresso machines, barbecue grills or why we don't want to discuss Agile evolves. The day can come.

9:10 am: Time to do some work! And, no, that doesn't involve foosball. Or ping pong. I'm actually writing code. Unfortunately I am not allowed to chat about what we do, or even how we do it. So just imagine me typing. And talking to people. And typing again. More talking. More typing. You get the idea.

Lunch at Pintxo12:10 pm: The hardest question at lunch time is which cafe to choose. I just run with the crowd of people working next to me. Today we're heading over to Pintxo. One thing that constantly surprises me about food at Google is that I actually like the dessert. Chocolate cookies, sliced fruit, hot brownies, some chocolate cream topped with strawberries. Take your pick.

1:00 pm: Work, work, work. Getting some coffee. Work, work, work. More coffee. Work, work, work. Grabbing a snack, which leads to some discussion about pair programming and the state of the world in general. Work, work, work.

7:30 pm: Going to Charlie's to get my usual treat for the evening: a self-designed burger and a coke. This certainly feels like America. I meet Nicolai and his friend, who doesn't work for Google. I learn that we're allowed to bring visitors to dinner one or two times a month. We talk about real estate prices and I realize that living here is even more expensive than Munich. Dang!

Mountain View Shoreline8:15 pm: I finally arrive at the apartment. I kill half an hour by starting Yet Another Blog Post. I want to write something about unit test size that features some modestly comical adult references (go figure). After some time I realize that I don't have enough high energy content for this entry. I'll finish it eventually. Blogger's shortest joke.

9:00 pm: A new episode of House starts. For some strange reason the ability to watch a show that doesn't run in Germany yet makes me feel childishly happy. This probably reveals things about my personality I don't even want to think about.

10:00 pm: The favorite part of my day is talking to my wife. And this is PRIVATE! ...

10:30 pm: Another day at Google passed. I do some reading and eventually fall asleep. Just for the reference: my dreams are private, too. Just in case you'd hoped for something. Good night!

Tuesday, March 11, 2008

An Editor Independent Unittest Executor

Since I got test infected I'm somehow unable to write a single line of untested code without feeling uneasy. When I just want to write a tiny script containing a few lines of code in whatever text editor is installed in a system, it seems to be a daunting task to set up a programming environment that allows you to execute unit tests with a single click. But this single click is what makes writing unit tests unobtrusive enough to keep doing it.

So I'm quite fond of using a simple script to execute my script's unit tests whenever I save it. This concept is not new, and certainly not an original idea in itself, but the simplicity of an editor independent unit test executor in 10 lines of code has a certain appeal for me:

#!/bin/bash
stat_command="stat -c '%Y'"
file_name=$1
last_modification=""
while true; do
current_modification=$( $stat_command $file_name )
if [ "$current_modification" != "$last_modification" ]; then
clear
$file_name --test
last_modification=$current_modification
fi
sleep 1
done

This script stats the script file until it detects a change. Whenever a change is detected, the script is called with --test, which is my personal way to tell a script that it should just execute it's unit tests and exit. See my blog post about integrating unit tests in Ruby scripts to learn how this can be done in Ruby. A very similar approach is possible for Python:

#!/usr/bin/python
import unittest
import sys

if sys.argv.count("--test") > 0:
sys.argv.remove("--test")
unittest.main()


Now I can simply call the test bash script, giving it the script under test as parameter:

./run_tests.sh ./script_under_test.py


The beauty lies in the simplicity of the solution: Even when I remote edit a script on some server with vi, I can simply launch a new console and execute run_tests.sh, watching the test results whenever I type ":w".

Update: The "sleep 1" really helps to keep I/O load down. Thanks to Philip for pointing this out. And yet another nice example of how hard it is to write 10 lines of bugfree code without a test.

Monday, February 4, 2008

Integrating Unit Tests In Ruby Scripts

When I write ruby scripts I like to use a single file, containing the program and all unit tests. It took me some time to find out how to add a command line switch to my ruby scripts that makes them run in script mode with full access to the Test::Unit command line arguments, while being able to run the script without the test framework interfering in the execution:


#!/usr/bin/ruby -w
require 'test/unit'

if ARGV.include?("--test")
ARGV.delete_at(ARGV.index("--test"))
else
Test::Unit::run = true
puts "Running..."
end


Now you can simply run the program by typing

$ ./testme.rb
Running...

or run the tests with

$ ./testme.rb --test
Loaded suite ./testme
Started

Finished in 0.0 seconds.

0 tests, 0 assertions, 0 failures, 0 errors

The nice thing is that only the first "--test" will be removed, so you can still leverage the Test::Unit command line argument interface.