The issue with dynamic languages mostly is that it's sometimes next to impossible to find all references to the code you're refactoring, so you can't just rely on a compiler & tests to ensure that nothing breaks after a change in some core library that everyone uses. Instead you almost have to add some logging into a function you're refactoring, make sure it's not used after you've made the change to a new API, and ideally do that a couple times. It's not too bad when you're the sole developer in a repository, but in the presence of hundreds of feature branches that sometimes can be weeks old, you can't be sure that nothing breaks after your change in the future too. So unless your code can be statically analysed reliably (like in compiled languages) large scale refactoring is a huge pain