That makes almost everything breaking.
That makes almost everything breaking.
Going back to the original article, it seems reasonable to me that the following qualifies as such a user-observable change:
foo(null) # throws InvalidArgumentException
updated_foo(null) # the same as foo(0)This isn't a breaking change because up until that point any code that was written to use that method already wasn't passing null (because it couldn't, because it wouldn't compile). The method's behavior hasn't changed, just its type signature, and so for any of the arguments that the existing code might possibly pass to it, it will still handle all of those exactly the same as it would have before (because, again, the implementation did not change).
Therefore, it is not a breaking change.
Yes, in most programming languages/environments it is always possible to write your application in such a way that any change of a dependency is I’ll break your app. Heck, you could throw an exception if someLib.version != “1.0.2” and then complain that a patch to 1.0.3 is actually a breaking change. Or your app could test that some API method does not exist, then complain when that method gets added later. Or you could complain when performance improvements reveal race conditions in your app (or break your usage of your computer as a space heater).
We can divide those breaking changes into two:
1. The call obeys the specification.
2. The call, though apparently successful, circumvents the specification, relying on undocumented behavior.
The question is how much we care about 2, and there is no 100% answer.
There can be situation in which some kinds of 2 breakages are such that we care about them more than 1 breakages.
Suppose there is a certain correct, documented way of using the API, but almost nobody out there uses it that way. And suppose there is some undocumented way of using the API, which millions of installations use, thousands of times per second.
Suppose we need to implement something new, or even ore importantly, fix a critical bug, and suppose that the work boils down to either breaking one, or the other. It may be better to break the former to keep the latter working (and possibly elevate the latter to documented status).
In other words, in a perfect world we'd like to say that breakages of type 1 are non-negotiable, whereas 2 can be debated. But we can't even do that.