[Interest] Using a single shared Object as a message bus throughout the application?

Tarre Tarkas mail.tarre at simplelogin.co
Wed Jun 9 21:11:51 CEST 2021

I'm working on a daemon that needs to stay flexible/tweakable. I get 
lots of random requirements in the form of "system needs to do X when Y 
happens and if conditions A B and C are met".

Qt's doc and examples seems to exclusively encourage putting signals in 
each component's class definitions. So that's what I did previously. 
However I recently found out that you can actually emit a signal in a 
different QObject. I always thought the "emit MySignal()" to be like a 
private call, but no, signals are public functions, you can do 
"someobj->MySignal()", or better yet "Q_EMIT someobj->MySignal()" to 
make it stand out more.

I'd like to hear your thoughts on an application architecture style 
where you use a single shared object as a public message bus throughout 
the entire app. So all the components of the app have a reference to 
this QObject, all the "public" signals used by the application are 
defined in this QObject instead of being defined in the object that 
emits them.

I've written a very simple example app to showcase this: 

Notice how the features in the 2nd and 3rd commits were bolted on to the 
existing architecture in a very straight-forward way, without having to 
modify unrelated source files.

1) Simpler application architecture. Since there's just a single source 
of major events, a new developer doesn't need to understand (as much) 
where their code fits with all the rest. They can add certain features 
by just writing signal handlers for signals coming from that single 
event bus. Also, they can discover how components interact with each 
other by searching for the usage of each signal from that single file. 
When writing new components, they don't need to think as much where to 
place it, since there's already this structure in place.
2) Signals emitted by objects created at a low "depth" (for example 
Hardware -> SensorManager -> TemperatureSensor) can be used by 
components anywhere in the app in a simple clean way, without writing 
repetitive boilerplate code just to be able to connect a signal to a 
3) If there's a refactoring somewhere, if a different component is now 
responsible for emitting SignalX, consumers don't have to change 
anything. Previously the only way to do this would be to use interfaces, 
which is boilerplatey.

1) Not Qt-ic (whatever the Qt equivalent of "pythonic" is)
2) You lose the ability to use sender() to get a reference to the 
QObject* that did the real emit. With this, the sender is always the 
message bus object. (Correct me if I'm wrong. If there's a way to get 
the sender without adding it as an argument in every signal, that would 
be wonderful.)

What do you think?


More information about the Interest mailing list