Создаем либу, которая предоставляет общее sdk, обычно это набор абстрактных классов. Создаем класс Plugin, который содержит в себе необходимые точки входа, обычно это init для того, чтобы плагин сказал о том, что он умеет, load для того, чтобы плагин начал выполнять возложенные на него фичи и unload, для выгрузки. Далее делаем менеджер этих самых плагинов, который имеет в себе указатели на все доступные плагины, он уже разруливает что загружать, а что нет, а также разруливает всякие штуки наподобии зависимостей между плагинами.
Работать такая связка будет столь же быстро, как и монолитное приложение, зато каждый плагин будет являться лишь кирпичиком и можно будет гораздо проще отлаживать. Такого рода незначительно влияет на скорость загрузки приложения (необходимо таки делать некоторые лишние телодвижения в рантайме) и незначительно на объем потребляемой памяти. Можно организовать обмен эвентами между плагинами, но гораздо проще и быстрее сделать плагины реализациями некоторых интерфейсов, а обмен событиями использовать лишь в небольшой части плагинов, где это реально нужно.