I suspect the reason why most exploit code is so messy to read is that while writing the exploit you're still figuring out the "architecture and language" of the thing you are attacking.
There are so many false starts, and so many false assumptions when you start.
A simple false assumption can start you down a wrong path for weeks... but often you can't easily verify that it is false before starting.