"A 'spec' is close to useless. I have _never_ seen a spec that was both big enough to be useful _and_ accurate. And I have seen _lots_ of total crap work that was based on specs. It's _the_ single worst way to write software, because it by definition means that the software was written to match theory, not reality."
I totally agree. If you want to understand something you simply must adhere to the Masaaki Mantra: "You must read the code." Documentation is helpful in getting you part way there, but there's no way in hell that the documentation 100% matches the code. This is the essential problem with Microsoft and other closed-source software. The documentation is usually close, but rarely on target. I can't see the code to know what's really happening.
It is my opinion that the best "specification" for code is more code. This is the basic philosophy of Damian Conway's Perl Best Practices (see Ten Essential Development Practices for a summary). This is a software engineering strategy with which I can agree. (I despise all that UML crap.)
Basically, if you want your code to work well. Design your code interface first. Build your tests second. Finally, fill in the details of your implementation. I'm not in a good habit of building things this way, to be honest, but these are habits every developer should work on. As part of interface design, test writing, and implementation, you should be documenting and updating your documentation. Then, your documentation can help a programmer get started, but when they want answers your docs don't contain, they can read the code. By examining the interface directly and looking at your test cases, they can understand what you intend. Finally, by reading the implementation, they can find out how it really works.
Mr. Torvalds, you rock. Software specs suck!