Если говорить о высокоуровневой архитектуре приложений, то я в последнее время сталкиваюсь с двумя подходами: шина событий (event bus) и flux/redux. В клиентской части популярнее вторая, в серверной - первая (за счёт популярности микросервисной архитектуры). У обоих подходов есть свои плюсы и минусы, серебряной пули нет. Для обоих подходов есть соответствующие библиотеки в документации к которым обычно описаны best practices.
Кроме того, не стоит бояться писать говнокод, особенно для своих проектов. Вы не научитесь писать хороший код, если не будете знать, что такое говнокод. Напишите так, как можете приложение до работающего прототипа, а потом, в следующей итерации, подумайте, как можно сделать лучше. Преждевременная оптимизация - главный враг перфекциониста!
P.S.: забыл добавить, что прямые взаимные зависимости между компонентами - это действительно наихудший подход. Оба описанных подхода преследуют одну цель - избавиться от этих зависимостей.