Что приходит на ум:
1. Пользоваться только открытыми интерфейсами, если задание не укладывается в таковые воркэраундить или говорить, то такое невозможно - плюсы - больше вероятность обратной совместимости, минусы - ограниченность
2. Заменять более крупными кусками (Можно посмотреть на SubledgerJournalizerBondExtension - вместо того, чтобы как-то встроится в системную группровку, заменяет ее полностью). Плюсы - больше можно сделать, минусы - дублирование кода, надо протаксивать что-то при фиксах в расширяемом коде.
3. Грязные трюки (например рефлекшн для доступа к приватным методам,
Moles) - Плюсы - больше возможностей чем 1. меньше кода чем в 2.. Минусы - сломается при апгрейде.
Вообще говоря, вся штука в том, чтобы вендор мог выделить такие интерфейсы которые:
1) Были бы достаточны для расширяющих
2) Сам вендор имел практическую возможность их не ломать.
При любом подходе
будут расширения которые ломаются - просто разная вероятность. Как в винде - блокнот скорее всего заработает, расширение меню explorer скорее всего тоже, но с меньшей вероятностью, а антивирус скорее всего нет (ну или что-то такое странное).
Вопрос в том, чтобы отделить одно от другого.
Интересен также подход в опенсурс проектах - большинство софта пишут используя API но если надо чего-то еще, то можно предложить патч (насколько я знаю, даже MS патчил линукс, чтобы поддержать Hyper-V), если патч будет хорошим (по стандартам кодировния, документированным) то есть вероятность что его вольют в версию продукта.