Dumb code, easily revertible has been, by far, the most effective way to prepare for changes in my experience.
Anything trying to be too smart, too generalised, too decoupled with plugable parts and it has a huge potential to become an entangled mess. While dumb code can be read and reasoned about quickly, if a change is easily revertible you can plug back the dumb code and try again without losing momentum.
Decoupling and composition are absolutely powerful tools to make good code but unfortunately I've seen both being used to create ad hoc plugin systems that were simply absurd to deal with in microservices.