The only way to adress (but not eliminate, since it's impossible) technical debt is to refractor mercilessly and constantly. And then there is some merit to static type advertisement - as the tools and techniques to safely refractor are both more feasible and more available for these environments.
Hark! A counterexample has arrived! I spent a bunch of years creating and maintaining big Rails applications. I've spent the last couple years on a bigger application in Java. I didn't drink any kool-aid, I just think Java is a better tool for this. C# and other things may be even better; the key is the ability to write static analysis tooling, which includes, but is not limited to, a compiler's type-checking analysis. It's not that a language with strong static analysis support saves you from creating a mess, it's that it makes it easier and much less risky to clean up that mess over time.
I agree with everything in your second paragraph, and would emphasize the risk aspect of refactoring a big application without good static analysis tools. After the first few spooky-action-at-a-distance prod breakages due to refactoring, it becomes hard to argue for a merciless and constant refactoring culture, and much easier to become the grizzled veteran who is a risk averse gatekeeper discouraging major refactoring in code reviews (this was me).
That and: You don't (or at least shouldn't) write a big application anymore. The only other thing (other than horizontal scaling, that is) that microservice design makes easier is exactly code maintainance / refactoring. The practices around it have matured enough.
On the other topic: I've spent last year or so writing mostly JavaScript, and have moved to VS Code as my primary IDE. I'm pretty happy (was doing Java/Python before that, and PHP/Python before that, and some embedded stuff before that).
The truth is that a good tool (and VS Code is one hell of a tool) makes working in a dynamic language very usable. VSCode static analysis tools make my JS experience better than my previous NetBeans Java experience, all things considered.
And I'm now dabbling with TypeScript to see how that goes. I quite like the idea of "just enough typing" and I think type-hinting rather than static typing is the way forward in this networked future. It's simply that these JSON-ed distributed environment people work in now will make static typing languages frustratingly un-agile for large majority of use-cases.
I've worked with large rails, django, and node apps, and none of them have felt particularly enjoyable to work with from a feature development standpoint once a certain scale is achieved. This doesn't feel like a rails-specific problem to me, but that's just based on my experience.
You can architect clean software in any language. What happens is this: you learn a new framework (or sometimes learn a new framework AND the corresponding language it is build in). You don't know what is idiomatic. You haven't made mistakes yet. You're making progress on your idea and getting shit done though, so it doesn't matter. Long story short: you don't know any better. Hindsight is 20/20!
Next time around you try something new and blame your old woes on the framework. This time around you've learned a thing or two about how to properly organize your code. You've been bitten by a third party tool that stopped being maintained. You've grown and learned and become more wise. But... you still blame your past issues on the old framework.
At some point you've been doing this for decades and you start to learn about abstract patterns that are not coupled to frameworks: service-oriented design, domain-driven design, CQRS (command driven systems), event buses and event systems, clean architecture, separation of concerns, SOLID principles, etc... ONCE you are at that point, you will begin to realize that NONE of the frameworks are going to solve these issues and NONE of them are more or less prone to causing tech debt.
Long story short: keep building software and focus on principles not frameworks. Read up on SOLID. It just takes time to get better and to start building things that don't encourage debt.
Another thing to note: tech debt is not bad. People throw that term around all the time and use it as a proxy for "messy code". Nothing in life is free. Everything is a balance. Perfectly architected software vs move fast and prove the business and make a profit? Pick one. You're going to acquire some amount of tech debt along the way. It's like real debt... sometimes you gotta accrue monetary debt to make progress elsewhere.
Parent is definitely right, projects that are "designed right from the beginning" do not exist in reality. Everything has unknowns in the future, and it is better to be flexible and adapt the code base to them as they come rather than trying to plan everything out from day 1. Static typing does help with these adaptations, but it doesn't compensate for a lack of diligence in keeping the code clean as the software grows.
I'm not sure Ruby, Python, Javascript, etc. were really designed for large scale development (although people use them for that). I think this is the primary reason so many people complain about technical debt, hitting the wall/limit, needing to refactor, etc. And looking for another language. Their tools just were not meant to scale that large.
"Go was deliberately designed from the start to support large scale programs implemented by hundreds or thousands of different programmers. Those kinds of programs are written at Google, and Go was designed to be used to write programs at Google." - Ian Lance Taylor
More from Ian here - https://www.quora.com/Will-the-Golang-code-become-unmaintain...
Yeah, that's basically what invalidates the assertion. There's no language or framework that guards against the complexity of a large code base. Period.
Don't pin this on ROR. I have seen absolutely atrocious Django codebases, Clojure projects, etc...
Types do not solve this problem either. If you think static types prevent 'tech debt' you're delusional.
Good architecture can be had across the entire spectrum of tools and frameworks.
At this point I have a strong aversion to starting any product using a dynamically-typed language (regardless of framework). The initial speed and ease of development is repaid 10x later on in sheer engineering pain (if you're lucky enough to be successful, that is).