After a fairly frustrating evening trying to get a service configured on a pet project (I won, Nomad is now running) I've realised what's been bugging me about Ansible (I think this applies to Chef, Puppet and Salt too, don't quote me on that though): it doesn't store any state, nor does it come up with a plan.
Compare to Terraform, which is both a joy to use and frustrating in how deliberately limited it is. It keeps a snapshot of server state, compares the current server state to that and comes up with a plan of action. You can even save that plan and pass it around for future application by someone else. It's essentially a Makefile for your servers (it even lets you write the DAG to Graphviz for visualisation).
It's also fast, I can quickly see what my edits will do. Compare to Ansible where I wind up commenting out swathes of my tasks to get to the spot I'm debugging quickly. Yeah, yeah, tags, I know. I shouldn't have to do this stuff ahead of time.
With state you can spot deletions too, solving that annoying problem of having to keep a "file: ... state=absent" line around to remove mistakes.
With a DAG you can spot config cycles too, and order tasks correctly. Just tonight I had an impossible problem where I was switching bind ports of a service but a command to talk to it was invoked before the restart handler in Ansible. I commented out the line, ran the play and uncommented it again.
All in all, yay Terraform, boo-erns Ansible. Though as I've said many times before, Ansible is the least worst option out there when it comes to config management like this.
I think it's time for me to bake more stuff into images with Packer just so I can use Terraform more :)