- Documentation is great, but documentation can fall out of date. Strong types usually can't; they are checked in both directions.
- Tests are great, but it's hard to maintain 100% coverage that checks all of what types do. It's very possible to have tests that pass that shouldn't. Types can not only find stealthily broken code, but also broken tests.
- Type checking gives even more instantaneous feedback than almost any test runner.
- Most projects have multiple developers. Types don't communicate everything, but they are a reliable form of communication that is guaranteed to be up-to-date even when documentation isn't, which is great combined with good function names and good parameter names.
- Most programs need to deal with requirements that shift, either because they evolve or our understanding evolves. Refactoring code without types is hard: if you change the return value of something, how can you be sure that all of the usages are up-to-date? What about if your refactor has been rebased a number of times before merging? I've run into a real-world production incident caused by this, when a return type changed to a tuple and it only exploded in an important Celery job that didn't have a test around the specific boundary that broke.
"If you know what you're doing" is not enough. Programs change, and they are changed by multiple people concurrently. This is the same reason why Rust continues to grow, people can say what they want but moving errors to the left is the only way forward because even if you're literally perfect you still have to know 100% of what's going on to never merge anything that causes a problem. (But really, people are not perfect, and never will be, so better tools Will win eventually.)
> - Most programs need to deal with requirements that shift, either because they evolve or our understanding evolves. Refactoring code without types is hard
I get perverse thrills out of drawing the attention of the "pfft, types are for n00bs" crowd to the multiple authentication related CVEs in GitLab due to the "well, the parameter types are whatever they are, don't you worry about it"
That said, I'm trying very hard to ween myself off even reading these threads, let alone contributing to them, because much like <https://news.ycombinator.com/item?id=42492508> I'm never going convince them and they for damn sure are never going to convince me
- Tests are great, but it's hard to maintain 100% coverage that checks all of what types do. It's very possible to have tests that pass that shouldn't. Types can not only find stealthily broken code, but also broken tests.
- Type checking gives even more instantaneous feedback than almost any test runner.
- Most projects have multiple developers. Types don't communicate everything, but they are a reliable form of communication that is guaranteed to be up-to-date even when documentation isn't, which is great combined with good function names and good parameter names.
- Most programs need to deal with requirements that shift, either because they evolve or our understanding evolves. Refactoring code without types is hard: if you change the return value of something, how can you be sure that all of the usages are up-to-date? What about if your refactor has been rebased a number of times before merging? I've run into a real-world production incident caused by this, when a return type changed to a tuple and it only exploded in an important Celery job that didn't have a test around the specific boundary that broke.
"If you know what you're doing" is not enough. Programs change, and they are changed by multiple people concurrently. This is the same reason why Rust continues to grow, people can say what they want but moving errors to the left is the only way forward because even if you're literally perfect you still have to know 100% of what's going on to never merge anything that causes a problem. (But really, people are not perfect, and never will be, so better tools Will win eventually.)