Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I find that strong typing often obviates the need for unit tests.

Software breaks when data transforms in a way that typing can't solve. When data goes across a wire, or into a database, it leaves your space. Anything you do to your code risks breaking it. Integration tests solve that, but at a very high cost.

I don't have a great solution for that. It just comes down to experience: how do things change over time? You take guesses. You try to be flexible, but not so flexible that you aren't solving the problem at hand. (It doesn't do you any good to hand the user a C compiler and say "this is flexible enough to handle all of your future needs.")

Experience is, unfortunately, the worst teacher. It gives the lesson after it gives the test.



> I find that strong typing often obviates the need for unit tests.

Can you expand? Because my experience is they are totally orthogonal.

For me, unit testing is to ensure the function's algorithm is correct. You verify add(2, 3) == 5 and add(1, 2, 3) == 6 and add(2, Null) == Null.

But you don't generally write unit tests that tests how a function behaves when you pass an unexpected type. Nobody in my experience is testing add("a", FooObject) for a function only meant to take ints or floats, to make sure it only takes ints or floats.

So they solve entirely different problems: strong typing ensures a caller provides compatible data, while unit tests ensure a callee produces correct results (not just correctly typed results) from that data. You want both, ideally.


> Nobody in my experience is testing add("a", FooObject) for a function only meant to take ints or floats, to make sure it only takes ints or floats.

If it's a dynamically typed language and you want to be sure that your method throws an error on invalid types (rather than, say, treating the string "yes" as a boolean with a value of true), then unit tests are a good use for this.

I would argue that failing fast (for cases like that, where an input "could" be treated as the type you want, but almost certainly the caller is doing something wrong) is a positive thing.


For certain classes of dynamically typed languages the unit test serves the function that a compiler or linter would perform just by running the code on any input to ensure it can run at all. Basically since these checks are runtime instead of compile time, you have to run the code to get even basic syntactical checking. I think ruby, python and JavaScript all used to use unit tests in this way. These days static analysis tooling is much more advanced and can provide much of the same benefit without running the code, but I think this is where the idea of 100% line coverage comes from.

Strong typing certainly doesn’t remove the need for testing, but it does change what type of issues you test for. And for certain classes of boring code that just transform or move data, a single integration test can give you all the assurance you need.


That is because typing in this case is converting a semantic (run time) property into a trivial property (T/F).

It is just making a trade off that is often a reasonable pragmatic default, but if taken as an absolute truth, can lead to brittle systems stuck in concrete.

Not all problems can be reduced to decision problems, which is what a trivial property is.

For me looking at how algebraic data types depend on a sum operation that uses either tagged unions or disjoint unions is a useful lens into the limits.

Note that you can use patterns like ports and adapters which may help avoid some of that brittleness, especially with anti-corruption layers in more complex systems/orgs or where you don’t have leverage to enforce contracts.

But yes if you can reduce your problems to decision problems where you have access to both T and F via syntactic or trivial semantics you should.

But when you convert pragmatic defaults to hard requirements you might run into the edges.


Agreed about strong typing being a valuable tool, especially static typing.

We've come full circle with coworkers telling me that "the best thing" about LLMs is that they can tell you when you have a typo in your function invocation or you forgot a mandatory parameter. This always leaves me dumbfounded, mouth open. If only we had a system to prevent this, from before LLMs!


Strong typing does not obviate the need for unit tests. It just obviates the need for the simplest ones about passing incorrect types. These are now being obviated anyway due to typecheck static analyses being added to most commonly used untyped languages (python and typescript over javascript, for example).


> strong typing often obviates the need for unit tests

Do languages like Java have strong typing?

I thought so, but I can’t reconcile that with the belief that unit tests in Java would be unnecessary.


It's reasonably strong, so that on practice you can trust it to verify the properties it verifies. (Though, it's not completely flawless in theory.)

It's also static, so your types declarations will replace tests.

But it's extremely inexpressive, so you can declare very few properties, and so it will replace very few tests.

And it's inflexible, so it will get on your way all the time while you program.

Anyway, I can almost guarantee you the GP wasn't talking about Java.


There's no single definition of strong with respect to typing, but I would probably put Java into the weaker of type systems, though it has gotten better over time. You can usually tell by how many casts you see in the code, and with most java codebases I see them everywhere. The pervasive nulls and untyped arrays are also huge red flags.


> I find that strong typing often obviates the need for unit tests.

There are many ways that software can fail, and unit tests cover some of them. They don't remove the need for unit tests at all, but they do reduce the number of them needed (because you no longer need to test the things that strong typing handles).


I usually test behavior, not interfaces or implementation details.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: