A psychological analysis of why programmers don't document enough, given in the form of an analogy:
Making a Will
If you make a will, your children will thank you for it. Not now, but in the future, when you die.
But who wants to think about the future? (And who wants to think about their own death?)
It would be easy to make a will now, but you don't need a will now, because you're not dead, and as far as you know, you're not going to die, not anytime soon.
Writing Documentation
If you write documentation, other programmers will thank you for it. Not now, but in the future, when you are not there anymore.
But who wants to think about the future?
It would be easy to write some documentation now, but you don't need documentation now, because you understand the code perfectly well, without any documentation.
Even if you didn't write the code, and you are the maintenance programmer maintaining it who has spent hours read the code to figure out what it means, now that you have understood it, you do not feel any urgent need to document the code.
The code may have been inscrutable when you started reading it, but now that you understand it well enough to be confident about changing it, you no longer see the need to document any of it. After all, as a result of your deep familiarity with the code, the meaning of everything in the code is quite obvious. And what's the point of documenting something that's obvious?
And, given that you've spent so much effort working on the code, no one else wants to work on the code now, so there isn't anyone else that you need to write the documentation for.
(I can't think of a better explanation ...)
This psychological explanation I have just given of why code is not documented seems trite, but there must be some explanation of why so much source code in the world is not documented, or not documented enough. (And yes, I sometimes look at my own code, and think: surely I didn't write so much code without writing any documentation!)
Action Point: Write For the Archaeologists
In 10000 years time, you will be gone, and everyone else who ever worked on the code will also be gone.
The only people who will read your code will be the archaeologists. Purely out of curiosity, they will try to understand your code, and they will try to understand what you were trying to do, and why you did it the way that you did it.
My advice is, help those archaeologists. They will be looking at your code, with none of the context of the knowledge that you have of what the code is for, or what data it processes, or what anyone does with the results. Write your documentation so that those archaeologists can more easily understand the greatness of your work.
You don't have to meticulously explain every little detail. (After all, it's not like archaeologists are stupid.) But don't leave any major mysteries. Don't leave the archaeologists staring at a Java class called PxddClaimsUpwardFactor.java, thinking What the f*** is this Java class for?. Put them out of their misery, with at least a little hint. And don't torture with them with documentation that only makes sense if they know a whole lot of stuff about other Java classes, which they won't know, because you didn't document those classes.
Actually, you won't really be writing for archaeologists. You will be writing for the person who has to maintain your software after you are gone. (And you will be gone, probably, because these days everyone moves around, from project to project, or from job to job.)
It might seem overkill to write for those imaginary archaeologists, because surely the person who comes after you will have at least some knowledge about the context in which your software is developed and deployed.
But it is so easy to over-estimate how much an unknown reader should know about something that you are documenting.
So forget about the imaginary programmer or programmers who will follow you, and write for those imaginary archaeologists.
They will thank you for it.