For the purposes of this discussion I will use the term application and system interchangeably to describe a piece of software with more than 300k lines of code and with more than 5 developers.
Dynamic programming languages allow you to make the Faustian bargain of ease of prototyping at the expense of maintainability. They let you prototype your system quickly without having to think too deeply about the core abstractions. In an application space where the core abstractions are hard to determine because the business is so new, this is a good thing. No point in thinking through the abstractions when you are building something radically new.
However, at some point, software becomes more permanent as the business it supports becomes more permanent. At that point in time abstractions become necessary to get engineering leverage. And then the Devil turns on you. Because the lack of abstractions early on make it hard to define them later. Worse, because of the dynamic nature of the language, it becomes hard to impose rules on the abstractions on the programmers. And as the team scales it becomes increasingly harder.
Over time you get a large piece of software for which reasoning about becomes increasingly more difficult.
And then you try and make the dynamic language more structured with more well defined abstractions and rules that the compiler and language and tools do nothing to help you with.
So the choice is always yours, pick a dynamic language and have no support when your business scales, or pick a structured language and struggled with the type-safety.
At the end of the day, you either believe types and abstractions make for productivity or you don’t. If you do, then you agree with me. If you don’t then you don’t. But 30+ years of programming language design has taught us that types do matter.