That's like saying "Maps can't represent truth". They're a model that works well enough, just like types do, if you do it right.
That's true for static types... but it's just as true for the constructs in your dynamically typed code! Nothing about dynamic typing makes your logic or data representation any more adaptable, it just makes the rigid models inherent to your code implicit rather than explicit.
I think that's why the article references the 'parse, don't validate' article: Real world data is messy and so you ingest it into your business logic at the system boundaries via parsing.
What do you mean? If a variable is a date/time or an integer etc. in the real world it should stay that way and be represented as such in software.
Same with a lot of systems like say a search system that tracks data using the best embedding, well we don't know what that best embedding is in terms of price performance and encoded knowledge perf it's just a moving target.
Send me the system that tracks important metrics effecting the stock market, or a weather system etc... the sensors are all updating and then an entirely new thing comes along like Starlink that helps us track the weather in totally new ways
As someone who is still learning this is a huge reason why I've come to love dynamic languages. Any project I do involves a lot of rewriting as the code evolves, I found that trying to predict ahead of time what the structures and types will be is mostly a waste of time. The best middle ground for me so far has been using python with type hints. It allows for quick iteration, I can experiment and only then update the types to match what I have, so that I can still get LSP help and all that.
But I could see this being less relevant with more experience
But yeah if you use something like Zod you can at least say "this is what I'm pretty sure the API should return" but also define what should happen if things change / don't meet your types.
This goes to the heart of what's not great about this, types impose global semantics on a piece of software, they introduce coupling. (It's why Alan Kay used to stress "late binding of all things") as a feature of managing complexity.
In fact one result of this kind of programming were microservices. What do they do? Reintroduce runtime dynamism. It's not often framed that way but there's a reason you see more statically typed microservices than Lisp or Erlang ones. It's because they're an attempt to get away from the coupling imposed by type driven programming and towards more independence of each service. Which is already baked into message based, dynamic languages.
And there's also a fundamental misunderstanding about data and types in the article.
> Making our types represent the “truth”
Types can't represent truth. Real world data doesn't have types. It changes incrementally however it wants, and all the time. You can use types to not let something you don't want into your program, but you can never represent arbitrary real world data by matching types onto them.