I realized that what he was really talking about was a form of semantic compatibility. My best real world example of semantic compatibility is when a component exposes events through it's interface. Although the interface is immutable the order in which events fire is not. So a component vendors may release a new version of a component for bug fixes or new features and not modify the interface but modify the order in which it's events fire causing a semantic compatibility problem.
The software development industry is doing a great disservice by not documenting event ordering through it's standard component documentation. Yes, we have BeforeActivate and AfterActivate through naming standards but does BeforeActivate come before or after BeforeInitialize? Got me! Let me test that. Oh, ok... now I know what it does. Is that what it's going to do on the next version?
So here's an interesting story I've told many friends:
Years ago I wrote a security component that handled all user password for encryption and decryption for system. This component was written in VB6 and used the CryptoAPI calls to encrypt and decrypt the passwords. As an example for calling the CryptoAPI I used this class from planetsourcecode.com I created full unit tests for encrypting and decrypting and everything worked great. The application shipped and the world is happy.
Now, we are migrating the system to .NET and one of the first components I needed to migrate was the security component. Unfortunately .NET 1.1 did not have native managed support for the algorithm I selected (CALG_RC4). No problem, I'll just implement the PInvoke calls as I did in the VB6 code.
I did that. Wrote unit tests and for some reason I was unable to decrypt passwords encrypted with the VB6 component. Passwords encrypted with the .NET component decrypted fine. Hmmmm, very odd. It turns out that the one of the hash parameters in the VB6 Crypto API declarations was defined "as String" when it should have been defined "as Any". This caused the hash to go through a unicode string conversion where the .NET code was not.
So now we have to inject a bug in our .NET code to maintain compatibility with a bug in our VB6 code. ARRRRRRGGGG!
A few of lessons here:
- Just because it passes all your tests does not mean it is correct.
- Don't use code directly off the internet (even API declarations)
- Once software is in the field you must maintain bug-for-bug compatibility and semantic compatibility.