I like Ansible, but it has flaws. I'm going to assume you know what Ansible is, and that you have used it before.
Basic Ansible is amazing, compared to the alternatives. When the alternative is half-baked bash scripts that rely on special environmental state, and obscure notation that is used infrequently, it is not hard to better it. I've used other automation tools too. Puppet is the other automation tooling that I've spent considerable time with. Puppet and I did not agree with each other as it required me to learn hundreds of special syntax rules almost immediately.
it is a fully fledged programming language
Ansible, on the other hand, makes you use yaml and various tasks with good documentation and does things in an orderly fashion that makes it simple to follow. It remains very basic for a while, up until it suddenly isn't, and you realise that it is a fully fledged programming language! A language with loops, and variable scoping rules, and conditionals, and then a sub-language (of Jinja2 templates) that means you can apply functions to lists and other variables. I went down this rabbit-hole for a while, and wrote some amazingly complex
map functions, that also used
combine, with some added pythonic teasers sown in... but then I stopped and wondered what I was doing. In this particular case, I invited some colleagues to my desk for peer review already knowing what they were going to say. "I don't want to maintain that". And thus, it was deleted.
Ansible can be basic, and it should remain that way. However, it is a programming language, and caution should be used in much the same way as caution should be used with any programming language. Make things clear. Prefer documenting 'why' instead of 'how'. Split things up, and reduce coupling between the pieces. Try not to mutate state if you can, and make sure it is tested. That last part is hard. Testing Ansible code is tricky. Very few bits are unit-testable as we're dealing with an operating system. Intrinsically, that is not a unit-test. It is an integration test, or a system-test. Having test VMs you can use and then destroy is a blessing, although not always available.
given the choice, I would make Ansible redundant
That sums up my views on Ansible itself. My current view on Ansible usage is perhaps slightly more nuanced; Ansible is a great tool, but given the choice, I would make Ansible redundant.
If you have to deploy on bare metal, without virtualisation, then Ansible is the answer... assuming you're not working on embedded systems, or within tight constraints. Most of my professional work is spent on systems that have ample headroom, and virtualisation is common though.
Given the choice, however, I would provision and deploy services using prebuilt images that are so incredibly basic that Ansible would be overkill. Simply: this JAR file lives here, and there's a JVM to run it. Bash scripts could handle that. The infrastructure would include the required configuration to run the applications, and it would all be defined elsewhere, in Terraform or CloudFormation or something else. I like immutable infrastructure. Immutability makes reasoning about things simpler, and making mistakes harder.
Unfortunately, there are a lot of organisations that don't have immutable infrastructure, and still rely on updating the same host with new code when they want to release something. Ansible for those organisations is a massive win.