Tests are also both code and documentation.
Or, you know, the design can also. If you're into having that.
well chosen function and variable names tell you the intention, if it's modular enough then it will all make sense when you read it.
If people could just get over this documentation phase that programming went through in the 80's and 90's due to languages containing obtuse syntax and being so low level you had to hold a dozen things in your head at once (I'm thinking of you COM) - but in this era, with languages that operate at a high level of abstraction the era of documenting the code is over.
"The code is the documentation only works if the code is immutable."
that's actually backwards. If you want to stand any chance of changing the code then it should be readable and well structured, not well documented.
"well chosen function and variable names tell you the intention, if it's modular enough then it will all make sense when you read it."
The two hardest things in computer science are concurrency and naming things. Oh, and off-by-one errors.
You look at code to determine what exactly the system does, but in order to determine what exactly the system should do, you need to look at the users needs or the business process, the code+comments can't tell you that.
I'm talking about being a user/caller of code, not attempting to fix it. Of course you need to know the innards if you're going to fix it, but needing to know all the implementation details in order to even call a piece of code is counter-productive. It's needlessly time-consuming and it violates the concept of separation of concerns.
very good point :)