4 ms·
>You're catching a set of errors (interface / types, method signature changes) that are difficult to catch in JavaScript without types when you're refactoring.
by spmurrayzzz 6y ago
>You're catching a set of errors (interface / types, method signature changes) that are difficult to catch in JavaScript without types when you're refactoring. Intended behavior is still validated with your set of unit tests.
I want to challenge this a bit. Your unit test suite should also be able to catch all these things with the right assertions. There's nothing about JavaScript, in either syntax or semantics, that make these especially difficult to test for (notwithstanding some of the more famous footguns, but those are well known).
To put it plainly... If I change the argument order of a function/method, the associated unit test absolutely should fail. If it doesn't, I'd argue the test wasn't written properly.
To me, this just smells like an ergonomics preference. As in— do you prefer writing unit tests or type annotations? The latter comes with some transpiling and dependency overhead, so I've just opted for the former.
(edited for grammar)
- striking 6y agoIt's not an either/or, the same way people who have access to professional editing staff probably still have a spell checker enabled in their word processor. If I have to hunt down each error caused by each refactor to the codebase, strictly based on a stack trace, I will not be happy. Being able to run a type checker that prints a list of probably wrong spots, and being able to check my unit tests after, makes me happy. And the overhead of introducing types is quite low, especially when using typesafe database tools like TypeORM and typesafe API tools like GraphQL. You basically get all your types for free. The question then becomes, why shouldn't we type check?
- spmurrayzzz 6y agoI don't think the assertion that types are "free" or "quite low" maps to my experience with JS tooling/dependency bloat. The transpiling burden is not minimal. I'm empathetic to the argument that because TS can find these errors easily, and descriptively, then it's a valuable tool. But your latter comment re: going through a stack trace, doesn't map to my experience with unit tests. If your test output is just a random exception in a stack trace, I would again argue that the test wasn't written correctly. This introduces an assertion burden for sure, ones you don't have to write if youre using TS, but I would posit that the exchange isn't as "free" as you claim.
- striking 6y agoWhy write assertions when TS can figure them out for you? And "tooling/dep bloat" is not a real thing. You point TSC at your code for prod, https://www.npmjs.com/package/ts-node-dev https://www.npmjs.com/package/ts-node-dev in dev. Frontend is even easier, create-react-app and Next.js and other project tools have TS support built in.
- spmurrayzzz 6y agoYou claim its not a real thing, and yet I have many practical experiences of it being a very real thing over the last 15 years of my career. Everything from simple tooling headaches in dev, to actual shipped production bugs resultant from the dev toolchain. Pretending like there isn't a real tradeoff here doesn't really help move the needle in my original commentary, that persuasive arguments in the OP article are missing. I also think its interesting that immediately subsequent to your comment about dep bloat not being a real thing, you link to yet another dependency to solve a problem with using TS in node dev. As an aside for what its worth (since you mentioned frontend), all of my commentary assumes node.js dev and not the frontend. The former is what I work in day to day. >Why write assertions when TS can figure them out for you? I could easily just reframe this to say: "why write type annotations when you can write assertions?" — its orthogonal to all my earlier points about the OP's arguments
- striking 6y agoI think if you're of the opinion that installing any toolchain (as opposed to writing files right to disk and having Node read them as-is) is "bloat" then obviously it will be hard for me to convince you it's not. I can say, however, that though your experiences may have been valid even as recently as a few years ago, there are very few bugs in these tools these days. Moreover, TS is not a place where these bugs appear; shipping prod code from TS source is literally just stripping the types as you check them, and whether you webpack/babel/etc. afterwards is up to you. In short, "bloat" could possibly be considered a real thing in other situations, but in the context of TypeScript it certainly isn't. Perhaps your previous experiences with these sorts of tools has affected your view of this one. I respect that. I just don't think it's relevant here. > "why write type annotations when you can write assertions?" Because you don't have to write type annotations most of the time (hence the "figures them out for you" that you omitted). TS infers them, even from things like database or API calls. We're not in Java land, where every type needs to be specified. TS understands what you mean, and will warn you (or configurably, throw an error) if it doesn't. It's a false equivalence.
- alpaca128 6y ago> Your unit test suite should also be able to catch all these things with the right assertions. A type system lets you precisely define the structure of your objects in the same language. It's a kind of documentation of implicit information that forces you to keep it up to date and write the annotations in a standardised way. It doesn't replace tests, but it is more precise, compact and you get near instant feedback after every modification of the code. The additional transpiling step might seem like a delay, but only if you don't consider the time saved by the type checker. When working with other developers it's also useful and gives me the structure of all their objects at a glance. And for me writing unit tests is pretty much one of the most boring and cumbersome part of development, second only to things like reading documentation in an attempt to figure out why that one DB installation is now malfunctioning since I pushed a commit in a different project during full moon. The fewer tests I have to write the better.
- spmurrayzzz 6y ago> A type system lets you precisely define the structure of your objects in the same language This is much more persuasive than anything written in the article I am commenting on. I personally still don't think this is worth all the tradeoffs for myself or team, but its a good argument for TS. > When working with other developers it's also useful and gives me the structure of all their objects at a glance Doc blocks also do this. A good argument could be made such that "if you're cool with writing doc blocks, why not write types while you're there?" - totally agree with that in principle. But again, in the aggregate cost/benefit analysis this is a minor win. >And for me writing unit tests is pretty much one of the most boring and cumbersome part of development I retreat back to comment I made about ergonomics preferences. You really dislike writing unit tests, I do not. TDD has been an incredibly impactful (and enjoyable) part of my 15+ year software journey. I started my career using strictly typed languages, and found my way out of them. Unit tests are one of the ways I maintain application integrity, which does actually (perhaps strangely for some) bring me joy. A buttoned up test suite is a very "feels good" moment for me as an engineer. Knowing I, or anyone else for that matter, can come back to the code later and both safely and confidently make changes. Something also worth noting, that didn't occur to me previously, is that my implicit heuristic analysis here is mostly centered around production node.js apps, not front-end apps. I haven't worked with the latter on a day to day basis in many years. Theres a significant difference in the cost/benefit calculus between the two. And a side point since we're talking in heuristics analysis... In my experience, especially my recent experience being a director of engineering & cofounder of a large technology company, runtime type errors are just not prevalent in the class of failure modes we see in our applications in production. I can't remember the last time a ReferenceError or TypeError appeared in any of our APM logs. So then the question becomes, how much time is "lost" in development when you hit type bugs (either with new code or fixing old code). This is much harder to quantify admittedly, but also seems minimal in my own experience.
- wtetzner 6y ago> I want to challenge this a bit. Your unit test suite should also be able to catch all these things with the right assertions. In general, tests can only find bugs, not prove the absence of them. Type systems, on the other hand, can prove that certain classes of errors cannot exist in the code. They are complementary, you want both. That being said, I don't think TypeScript's type system is sound, so it's probably not really giving you that benefit.
- spmurrayzzz 6y agoYou make a good point, that theres an inversion of responsibility here. Type systems can infer correctness, test suites have to prove correctness. I'm not sure this makes the toolchain overhead tradeoff a defacto major win, but its persuasive for sure. Curious if you could elaborate on why you don't think the TS type system is sound? I'm not familiar with any arguments to this end currently.
- striking 6y agoIt is unsound. One of the most impactful unsoundnesses is when you cast one array type to another compatible but not exactly equivalent type, and then write to the array. In Flow (another type system) you simply can't do that without making the array read-only at type level. In TS, they decided to allow this for ease of use purposes. Just in general, the TS team optimizes for a balance of bug catching and usability. It is a compromise. Flow is a much more advanced type checker that works even harder at inferring types and eliminating bugs at the type level. It's very cool! But its community is much smaller, the tooling isn't nearly as good, and it has some major performance issues. My workplace is migrating away from it in favor of TS, which is good enough without being too slow or incompatible with our tools.