Background:
I will be working on tools that will be dependent on a rapidly changing API and rapidly changing data model over which I will have zero control.
Data model and API changes are common, the issue here is that my code must continue to work with current and all past versions (ie 100% backwords compatibility) because all will continue to be used internally.
It must also gracefully degrade when it runs into missing/unknown features etc.
The tools will be written in C# with WinForms and are for testing custom hardware.
<Edit>
My goal would be something close to only having to create classes to add features and when data model changes come, create a new set of data model classes that will get created by a factory based on API version.
The challenge for me is that future features then may depend on the specific data models, which may be mixed and matched (until a final combo is reached). How would you handle this gracefully?
<Edit2>
Of course, once a product is shipped, I would like to reuse the tool and just add code for newer products. Before I started here, every product cycle meant rewriting (from scratch) all the tooling, something I aim to prevent in the future :)
</Edit>
Question:
What design techniques and patterns would you suggest or have had success with to maintain compatibility with multiple versions of an API/Data Model?
What pitfalls should I watch out for?
Practically all the SOLID patterns apply here, but particularly the Single Responsibility Principle (SRP) and Open/Closed Principle (OCP).
The OCP specifically states that the type should be open for extension, but closed for modification - that sounds like a good fit in your case, because this would be a way to ensure backwards compatibility.
The SRP is also very helpful here because it means that if a class does only one thing, and that thing becomes obsolete, it doesn't drag along a lot of other problems. It can just be left to die on its own.
On a more practical level, I would suggest that you follow two principles:
TDD (or just a comprehensive unit test suite) will help protect you against breaking changes.