I’ve been thinking about this aspect a lot myself. I think as an industry we’ve over-emphasized “declarative” as a silver bullet, when in fact it just isn’t well suited for a lot of situations.
If you look at the Kubernetes space, there are reems of YAML and configuration files. So much so that even more complex wrappers such as Ksonnet and Cue are built on top of it — trying to simplify the experience, while still being 100% declarative.
But at the end of the day, what is the problem you are trying to solve?
If your goal is to make it easier to understand how you are setting up your cloud infrastructure, then if you are setting up 100 EC2 VMs, having a “for loop” that executes 100 iterations is sufficiently clear.
Of course you can write super-complicated, difficult-to-maintain code using a real programming language. But that’s why we have code reviews, type checking, linters, style guides, etc. It’s easy to make code readable and understandable. When you are using a purely declarative model, you don’t have much flexibility.