clojure.spec seems like a powerful mechanism for ensuring the integrity of objects. I say that without having use this feature.
The issue of maintainability of untyped systems hinges on the ability of other people to understand one’s code. Object integrity is a separate problem, although an important one.
As an example pertaining to maintainability by other people, I have spent many hours trying to reverse engineer Python methods written by others, to discover what kinds of things the methods might return: does the method return one thing, or can it sometimes return an array of that thing? One cannot tell, since the type of the method is unspecified.
It surely saved the programmer a few seconds to not have to declare the return type — but cost me, the person trying to use the code — minutes or even hours, trying to figure out, with some assurance, what the method actually returns. I don’t want to have to guess when I use someone’s code.
A small team can easily maintain an untyped system, because they learn the codebase well: it becomes tribal knowledge. But if someone from outside the team must then use the code, it is a different matter. Many machine learning frameworks are in Python, as are many people’s machine learning models. That sometimes makes it very hard to understand and use other people’s models. I say that from experience.