There are two types of compatibility in software: new versions of programs reading old data (backward compatibility), and old versions of program reading new data (forward compatibility).
Backward compatibility is the easiest to achieve, as it does not require predicting the future. How can we ensure forward compatibility then? By imagining reasonable ways to extend the data format and making sure that the program works with these - e.g., doesn't break on unknown options. One suggestion has been to use a version number in your data format. However, I read that this failed for MIME, because no-one knew what the correct behaviour was if they got a different version number.
A related problem is interoperability. This refers to reading data produced by a program whose creation or maintenance is buereaucratically or socially separated from your control, and producing data to be read by this program.
How can we ensure interoperability? One way is that if you are inventing a file format or network protocol, make sure you define it thoroughly. Otherwise, other people will implement it all in slightly different, incompatible ways, and it will be impossible to be compatible with them all. (I heard that CSV was an example of this.) A similar way is make your data format as easy to parse as possible, otherwise other people may do it wrong. (See this page about different termcap versions for an example of a format with varying implementations.)
One way to encourage interoperability and backward compatability is intolerance of malformed syntax. This is a herbicide on the proliferation of degenerate data and means that new implementations do not have the burden of supporting degenerate data that people are relying on. How much you can get away with this depends on the share of usage of your program.