I'm honestly not sure if ND along with interface addresses in V6 is a useless hack, or if it is a clever trick. I keep changing my mind all the time. I guess it's kinda both.
On one hand, V6 addresses are big enough to represent hardware addresses directly. So you don't _need_ a low-level protocol like ARP to resolve V6 addresses to hardware addresses, you can represent it as special messages in IPv6 itself.
It also allows some interesting tricks, like local network applications using interface addresses to communicate normally without setting up global connectivity.
On the other hand, interface addresses in V6 cause no end of confusion ("what the heck fe80::88a:fd34:d1b:2de7%en0 means?!?"). And V6 also has no clear distinction between the local network and the Internet, and the easy ability to use broadcasts (just send a packet to the network address).
And it's not like many applications actually use interface addresses anyway. So this is kinda a moot point.