3 ms·
This post seems kind of incoherent. I think the premise is that, if you use the OTP properly, then you are generally protected from bugs by the properties of th
by MrJohz 4y ago
This post seems kind of incoherent. I think the premise is that, if you use the OTP properly, then you are generally protected from bugs by the properties of the OTP, and therefore you rarely (if ever) need to rely on testing or static type checking to catch those bugs. But I don't think the author is aware of the different value propositions of these tools - they each solve different problems, and work best in conjunction rather than separately.
With tests, for example, the big benefit is not checking whether code runs or not, it's checking whether the code does what you expect. I've been writing a surprising amount of code recently involving indices and slices of arrays, and it's often very easy to get that sort of code subtly wrong: including an element that shouldn't be there, missing one out, or surprising things happening when the list is empty. Types can't solve this problem, and it's unlikely that anything will crash per se, but you don't want to release to production and suddenly find duplicate data floating around the system because of some bad pagination code. Enter tests: I can write down a list of all the cases that are likely to be interesting, put together a test case for each one, and then make sure I've not forgotten anything in my implementation. Moreover, anyone who makes future changes can't accidentally break that logic, because the tests will keep on running. That's something tests can do that types and the magic powers of the OTP can't touch.
On the other hand, just today I was throwing together a quick reproduction script for a bug in a Python project. Because the aim was to find a minimal reproduction, there was a lot of refactoring going on - switching out libraries, adding and removing asyncio support, deleting functions, etc. Quite often, I'd make a change, and then need to make changes in other parts of the script to accommodate the changes (swap out a library -> change a couple of function names; add asyncio -> make sure everything is awaited properly, etc). Now I could have written tests for this script, but that would have taken ages and not been very useful. Or I could have run it and let it crash, as is the OTP motto, but even the takes time. But because MyPy is turned on by default in my editor, I got type feedback immediately on my code, which meant I could fix all the problems just by looking for the red squiggles. And sure, I still needed to run the code to make sure I could still reproduce this specific bug, but I didn't need to run the code just to see if it worked. The type checker solved problems for me that would have been slower if I'd been using just tests or a "let it crash" philosophy.
It seems to me that it is very useful to use each tool in the places that it is most valuable: tests to check that your code behaves logically and correctly; types to provide a sanity check and quick feedback on obvious mistakes; and the OTP to ensure strong reliability in the face of errors and bugs that slip through the other two defences. Using all three should surely give you better results than using one alone, especially if you use those tools according to their strengths.