Tabs are blatantly the correct answer.
Tabs separate code content from presentation. Indentation style becomes entirely personal, and each dev can adjust to their own tastes without affecting anyone else. Imagine that I have my editor set to tabs as four spaces. Then, I open a file from another developer who has tabs set as two spaces. Now, in order to write into his file, I have to go into my editor’s options and change my settings to reflect his convention otherwise the code that I’ve written will not match the code that he’s written. Bad times.
A tab character represents a single unit of indentation, so is semantically meaningful. It also stops people from mixing indentation levels or using invalid indentation levels (e.g. having a series of lines indented with 4 spaces with one or two lines indented with 3 spaces because of a mistake).
Tabs mean that editors don’t have to get clever, and stops me from having to backspace four times (or eight) instead of just one when I want to unindent.
Debunking common arguments against tabs
But then I can’t have arbitrary levels of indentation! What if I want to align my code, like this:
someVariable.SomeMethod(arg1, arg2, arg3);
Answer: Don’t do that. That’s really ugly. My rule is: “Never indent a line more than one level more than the line before it”. My version of the above would be:
someVariable.SomeMethod( arg1, arg2, arg3);
Or, if that’s still too long, then this:
someVariable.SomeMethod( someArgumentOne, someArgumentTwo, someArgumentThree);
But I want code I write to look the same on my colleague’s monitor as it does on mine!
The bottom line is this: using spaces for indentation is a hack; you’re mixing up indentation and code alignment, using whitespace to make things characters line up on screen rather than delineating blocks of code. Don’t do it.